django-keygen 0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mouhib Sellami
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
File without changes
@@ -0,0 +1,270 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-keygen
3
+ Version: 0.1.0
4
+ Summary: django-keygen is a Django management command utility designed to securely generate cryptographic secret keys.
5
+ Author-email: Mouhib sellami <mouhib.sellami@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/mouhib-Sellami/django-keygen
8
+ Classifier: Environment :: Web Environment
9
+ Classifier: Framework :: Django
10
+ Classifier: Framework :: Django :: 4.2
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Requires-Python: >=3.9
20
+ Description-Content-Type: text/x-rst
21
+ License-File: LICENSE
22
+ Requires-Dist: django>=4.2
23
+ Requires-Dist: python-dotenv>=1.0.0
24
+ Dynamic: license-file
25
+
26
+ django-keygen
27
+ =============
28
+
29
+ django-keygen is a Django management command utility for securely generating
30
+ cryptographic secret keys and passwords, and optionally writing them into your
31
+ project's environment (``.env``) files automatically.
32
+
33
+ Detailed documentation will be available in the "docs" directory.
34
+
35
+ Installation
36
+ ------------
37
+
38
+ Install via pip::
39
+
40
+ pip install django-keygen
41
+
42
+ Or install the latest version directly from GitHub::
43
+
44
+ pip install git+https://github.com/mouhib-Sellami/django-keygen.git
45
+
46
+ Quick start
47
+ -----------
48
+
49
+ 1. Add ``django_keygen`` to your ``INSTALLED_APPS``::
50
+
51
+ INSTALLED_APPS = [
52
+ ...,
53
+ 'django_keygen',
54
+ ]
55
+
56
+ Commands Overview
57
+ -----------------
58
+
59
+ django-keygen provides three management commands:
60
+
61
+ +---------------------------+-------------------------------------------------------+
62
+ | Command | Purpose |
63
+ +===========================+=======================================================+
64
+ | ``keygen`` | Generate secret keys and/or passwords into a named |
65
+ | | ``.env`` file. The recommended all-in-one command. |
66
+ +---------------------------+-------------------------------------------------------+
67
+ | ``generate_django_secret``| Dedicated command for generating a single |
68
+ | | ``DJANGO_SECRET_KEY`` and optionally writing it to |
69
+ | | an env file via an interactive or flag-driven flow. |
70
+ +---------------------------+-------------------------------------------------------+
71
+ | ``generate_password`` | Interactive terminal interface for generating and |
72
+ | | tweaking secure passwords. |
73
+ +---------------------------+-------------------------------------------------------+
74
+
75
+ ----
76
+
77
+ 1. ``keygen`` — Unified Key & Password Generator
78
+ -------------------------------------------------
79
+
80
+ The ``keygen`` command is the recommended way to generate one or more secret
81
+ keys and/or passwords and write them into an environment file in a single step.
82
+ Variable names are passed directly as arguments, so each generated value is
83
+ stored under the name you choose.
84
+
85
+ **Positional arguments:**
86
+
87
+ * ``SECRET [SECRET ...]``
88
+ One or more variable names to generate a Django secret key for (e.g.
89
+ ``SECRET_KEY API_KEY``). Each name receives its own independently generated
90
+ cryptographic key.
91
+
92
+ **Flags:**
93
+
94
+ * ``--passwords PASSWORDS [PASSWORDS ...]``, ``-p``
95
+ One or more variable names to generate a secure password for instead of a
96
+ Django secret key (e.g. ``-p DB_PASSWORD REDIS_PASSWORD``).
97
+
98
+ * ``--file FILE``, ``-f``
99
+ Path to the env file, relative to ``BASE_DIR`` (default: ``.env``). If the
100
+ file does not exist, the command offers to create it.
101
+
102
+ * ``--append``
103
+ Update the existing file in place rather than recreating it from scratch.
104
+ Without this flag the file is fully rewritten (all previous content is
105
+ preserved but reformatted alongside the new values). Prompts a confirmation
106
+ warning because replacing an active ``SECRET_KEY`` invalidates all existing
107
+ sessions, tokens, and signed cookies.
108
+
109
+ * ``--no-input``
110
+ Skip all confirmation prompts. Useful for automated deployments, Docker
111
+ entrypoints, and CI/CD pipelines.
112
+
113
+ **Examples**::
114
+
115
+ # Generate SECRET_KEY and write it to .env (recreates the file)
116
+ python manage.py keygen SECRET_KEY
117
+
118
+ # Generate two secret keys into a specific file, no prompts
119
+ python manage.py keygen SECRET_KEY API_KEY --file .env.production --no-input
120
+
121
+ # Generate a secret key and two passwords into .env.local, appending
122
+ python manage.py keygen SECRET_KEY --passwords DB_PASSWORD REDIS_PASSWORD \
123
+ --file .env.local --append
124
+
125
+ # Generate only passwords (no secret keys)
126
+ python manage.py keygen --passwords DB_PASSWORD --file .env
127
+
128
+ ----
129
+
130
+ 2. ``generate_django_secret`` — Dedicated Secret Key Command
131
+ -------------------------------------------------------------
132
+
133
+ The ``generate_django_secret`` command is dedicated to generating a single
134
+ Django secret key stored under the ``DJANGO_SECRET_KEY`` variable. Run it
135
+ without any flags to simply print a key to the terminal, or add ``--append``
136
+ to write it to an env file.
137
+
138
+ When writing to a file, the command either accepts a path via ``--file`` or
139
+ launches an interactive file-selection menu that scans your project for
140
+ existing ``.env*`` files.
141
+
142
+ **Flags:**
143
+
144
+ * ``--append``
145
+ Write the generated key to an environment file. Without this flag the key
146
+ is only printed to stdout — no files are touched. Prompts a confirmation
147
+ warning because replacing a live ``SECRET_KEY`` invalidates all existing
148
+ sessions, tokens, and signed cookies.
149
+
150
+ * ``--file FILE``, ``-f``
151
+ Directly specify the env file to update (e.g. ``-f .env.production``),
152
+ bypassing the interactive selection menu. If the file does not exist it is
153
+ created automatically. Only used together with ``--append``.
154
+
155
+ * ``--no-input``
156
+ Suppress all interactive prompts, menus, and risk warnings. Useful for
157
+ automated deployments and CI/CD pipelines.
158
+
159
+ **Examples**::
160
+
161
+ # Print a new secret key to the terminal only (no file changes)
162
+ python manage.py generate_django_secret
163
+
164
+ # Interactively choose which env file to update
165
+ python manage.py generate_django_secret --append
166
+
167
+ # Write directly to a specific file, no prompts
168
+ python manage.py generate_django_secret --append --no-input -f .env.local
169
+
170
+ **After running**, update your ``settings.py`` to read the key from the
171
+ environment::
172
+
173
+ import os
174
+ SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
175
+
176
+ ----
177
+
178
+ 3. ``generate_password`` — Interactive Password Generator
179
+ ---------------------------------------------------------
180
+
181
+ The ``generate_password`` command launches an interactive terminal session for
182
+ generating and refining secure passwords. After each password is shown, you can
183
+ regenerate it or adjust the composition settings without restarting the command.
184
+
185
+ **Flags** (set initial defaults; all can be changed interactively):
186
+
187
+ * ``--length LENGTH``, ``-len``
188
+ Desired password length (default: 12).
189
+
190
+ * ``--letters``
191
+ Include lowercase letters (a–z).
192
+
193
+ * ``--uppercase``
194
+ Include uppercase letters (A–Z).
195
+
196
+ * ``--numbers``
197
+ Include numerical digits (0–9).
198
+
199
+ * ``--symbol``
200
+ Include symbols and punctuation characters.
201
+
202
+ * ``--secure``
203
+ Shortcut that forces uppercase letters, numbers, symbols, and a minimum
204
+ length of 20. Overrides individual composition flags.
205
+
206
+ **Examples**::
207
+
208
+ # Launch with defaults (12 characters, no composition constraints)
209
+ python manage.py generate_password
210
+
211
+ # Start with a longer length and reconfigure interactively
212
+ python manage.py generate_password --length 16
213
+
214
+ # Instantly generate a highly secure 20-character password
215
+ python manage.py generate_password --secure
216
+
217
+ ----
218
+
219
+ Programmatic Usage
220
+ ------------------
221
+
222
+ The underlying password generator can be imported directly into your own
223
+ Django apps — useful for custom registration flows, invitation tokens, or
224
+ background tasks::
225
+
226
+ from django_keygen.core.passwords import generate_password
227
+
228
+ # Generate a secure password with specific character sets
229
+ new_password = generate_password(
230
+ length=14,
231
+ use_uppercase=True,
232
+ use_numbers=True,
233
+ use_symbols=True,
234
+ )
235
+
236
+ # Use it in your application logic
237
+ from django.contrib.auth.models import User
238
+ user = User.objects.create_user(username='johndoe', email='john@example.com')
239
+ user.set_password(new_password)
240
+ user.save()
241
+
242
+ ----
243
+
244
+ License
245
+ -------
246
+
247
+ django-keygen is released under the **MIT License**.
248
+
249
+ Copyright (c) 2026 Mouhib Sellami
250
+
251
+ Permission is hereby granted, free of charge, to any person obtaining a copy
252
+ of this software and associated documentation files (the "Software"), to deal
253
+ in the Software without restriction, including without limitation the rights
254
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
255
+ copies of the Software, and to permit persons to whom the Software is
256
+ furnished to do so, subject to the following conditions:
257
+
258
+ The above copyright notice and this permission notice shall be included in all
259
+ copies or substantial portions of the Software.
260
+
261
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
262
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
263
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
264
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
265
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
266
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
267
+ SOFTWARE.
268
+
269
+ See the ``LICENSE`` file in the repository root for the full license text,
270
+ or visit: https://github.com/mouhib-Sellami/django-keygen/blob/main/LICENSE
@@ -0,0 +1,245 @@
1
+ django-keygen
2
+ =============
3
+
4
+ django-keygen is a Django management command utility for securely generating
5
+ cryptographic secret keys and passwords, and optionally writing them into your
6
+ project's environment (``.env``) files automatically.
7
+
8
+ Detailed documentation will be available in the "docs" directory.
9
+
10
+ Installation
11
+ ------------
12
+
13
+ Install via pip::
14
+
15
+ pip install django-keygen
16
+
17
+ Or install the latest version directly from GitHub::
18
+
19
+ pip install git+https://github.com/mouhib-Sellami/django-keygen.git
20
+
21
+ Quick start
22
+ -----------
23
+
24
+ 1. Add ``django_keygen`` to your ``INSTALLED_APPS``::
25
+
26
+ INSTALLED_APPS = [
27
+ ...,
28
+ 'django_keygen',
29
+ ]
30
+
31
+ Commands Overview
32
+ -----------------
33
+
34
+ django-keygen provides three management commands:
35
+
36
+ +---------------------------+-------------------------------------------------------+
37
+ | Command | Purpose |
38
+ +===========================+=======================================================+
39
+ | ``keygen`` | Generate secret keys and/or passwords into a named |
40
+ | | ``.env`` file. The recommended all-in-one command. |
41
+ +---------------------------+-------------------------------------------------------+
42
+ | ``generate_django_secret``| Dedicated command for generating a single |
43
+ | | ``DJANGO_SECRET_KEY`` and optionally writing it to |
44
+ | | an env file via an interactive or flag-driven flow. |
45
+ +---------------------------+-------------------------------------------------------+
46
+ | ``generate_password`` | Interactive terminal interface for generating and |
47
+ | | tweaking secure passwords. |
48
+ +---------------------------+-------------------------------------------------------+
49
+
50
+ ----
51
+
52
+ 1. ``keygen`` — Unified Key & Password Generator
53
+ -------------------------------------------------
54
+
55
+ The ``keygen`` command is the recommended way to generate one or more secret
56
+ keys and/or passwords and write them into an environment file in a single step.
57
+ Variable names are passed directly as arguments, so each generated value is
58
+ stored under the name you choose.
59
+
60
+ **Positional arguments:**
61
+
62
+ * ``SECRET [SECRET ...]``
63
+ One or more variable names to generate a Django secret key for (e.g.
64
+ ``SECRET_KEY API_KEY``). Each name receives its own independently generated
65
+ cryptographic key.
66
+
67
+ **Flags:**
68
+
69
+ * ``--passwords PASSWORDS [PASSWORDS ...]``, ``-p``
70
+ One or more variable names to generate a secure password for instead of a
71
+ Django secret key (e.g. ``-p DB_PASSWORD REDIS_PASSWORD``).
72
+
73
+ * ``--file FILE``, ``-f``
74
+ Path to the env file, relative to ``BASE_DIR`` (default: ``.env``). If the
75
+ file does not exist, the command offers to create it.
76
+
77
+ * ``--append``
78
+ Update the existing file in place rather than recreating it from scratch.
79
+ Without this flag the file is fully rewritten (all previous content is
80
+ preserved but reformatted alongside the new values). Prompts a confirmation
81
+ warning because replacing an active ``SECRET_KEY`` invalidates all existing
82
+ sessions, tokens, and signed cookies.
83
+
84
+ * ``--no-input``
85
+ Skip all confirmation prompts. Useful for automated deployments, Docker
86
+ entrypoints, and CI/CD pipelines.
87
+
88
+ **Examples**::
89
+
90
+ # Generate SECRET_KEY and write it to .env (recreates the file)
91
+ python manage.py keygen SECRET_KEY
92
+
93
+ # Generate two secret keys into a specific file, no prompts
94
+ python manage.py keygen SECRET_KEY API_KEY --file .env.production --no-input
95
+
96
+ # Generate a secret key and two passwords into .env.local, appending
97
+ python manage.py keygen SECRET_KEY --passwords DB_PASSWORD REDIS_PASSWORD \
98
+ --file .env.local --append
99
+
100
+ # Generate only passwords (no secret keys)
101
+ python manage.py keygen --passwords DB_PASSWORD --file .env
102
+
103
+ ----
104
+
105
+ 2. ``generate_django_secret`` — Dedicated Secret Key Command
106
+ -------------------------------------------------------------
107
+
108
+ The ``generate_django_secret`` command is dedicated to generating a single
109
+ Django secret key stored under the ``DJANGO_SECRET_KEY`` variable. Run it
110
+ without any flags to simply print a key to the terminal, or add ``--append``
111
+ to write it to an env file.
112
+
113
+ When writing to a file, the command either accepts a path via ``--file`` or
114
+ launches an interactive file-selection menu that scans your project for
115
+ existing ``.env*`` files.
116
+
117
+ **Flags:**
118
+
119
+ * ``--append``
120
+ Write the generated key to an environment file. Without this flag the key
121
+ is only printed to stdout — no files are touched. Prompts a confirmation
122
+ warning because replacing a live ``SECRET_KEY`` invalidates all existing
123
+ sessions, tokens, and signed cookies.
124
+
125
+ * ``--file FILE``, ``-f``
126
+ Directly specify the env file to update (e.g. ``-f .env.production``),
127
+ bypassing the interactive selection menu. If the file does not exist it is
128
+ created automatically. Only used together with ``--append``.
129
+
130
+ * ``--no-input``
131
+ Suppress all interactive prompts, menus, and risk warnings. Useful for
132
+ automated deployments and CI/CD pipelines.
133
+
134
+ **Examples**::
135
+
136
+ # Print a new secret key to the terminal only (no file changes)
137
+ python manage.py generate_django_secret
138
+
139
+ # Interactively choose which env file to update
140
+ python manage.py generate_django_secret --append
141
+
142
+ # Write directly to a specific file, no prompts
143
+ python manage.py generate_django_secret --append --no-input -f .env.local
144
+
145
+ **After running**, update your ``settings.py`` to read the key from the
146
+ environment::
147
+
148
+ import os
149
+ SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
150
+
151
+ ----
152
+
153
+ 3. ``generate_password`` — Interactive Password Generator
154
+ ---------------------------------------------------------
155
+
156
+ The ``generate_password`` command launches an interactive terminal session for
157
+ generating and refining secure passwords. After each password is shown, you can
158
+ regenerate it or adjust the composition settings without restarting the command.
159
+
160
+ **Flags** (set initial defaults; all can be changed interactively):
161
+
162
+ * ``--length LENGTH``, ``-len``
163
+ Desired password length (default: 12).
164
+
165
+ * ``--letters``
166
+ Include lowercase letters (a–z).
167
+
168
+ * ``--uppercase``
169
+ Include uppercase letters (A–Z).
170
+
171
+ * ``--numbers``
172
+ Include numerical digits (0–9).
173
+
174
+ * ``--symbol``
175
+ Include symbols and punctuation characters.
176
+
177
+ * ``--secure``
178
+ Shortcut that forces uppercase letters, numbers, symbols, and a minimum
179
+ length of 20. Overrides individual composition flags.
180
+
181
+ **Examples**::
182
+
183
+ # Launch with defaults (12 characters, no composition constraints)
184
+ python manage.py generate_password
185
+
186
+ # Start with a longer length and reconfigure interactively
187
+ python manage.py generate_password --length 16
188
+
189
+ # Instantly generate a highly secure 20-character password
190
+ python manage.py generate_password --secure
191
+
192
+ ----
193
+
194
+ Programmatic Usage
195
+ ------------------
196
+
197
+ The underlying password generator can be imported directly into your own
198
+ Django apps — useful for custom registration flows, invitation tokens, or
199
+ background tasks::
200
+
201
+ from django_keygen.core.passwords import generate_password
202
+
203
+ # Generate a secure password with specific character sets
204
+ new_password = generate_password(
205
+ length=14,
206
+ use_uppercase=True,
207
+ use_numbers=True,
208
+ use_symbols=True,
209
+ )
210
+
211
+ # Use it in your application logic
212
+ from django.contrib.auth.models import User
213
+ user = User.objects.create_user(username='johndoe', email='john@example.com')
214
+ user.set_password(new_password)
215
+ user.save()
216
+
217
+ ----
218
+
219
+ License
220
+ -------
221
+
222
+ django-keygen is released under the **MIT License**.
223
+
224
+ Copyright (c) 2026 Mouhib Sellami
225
+
226
+ Permission is hereby granted, free of charge, to any person obtaining a copy
227
+ of this software and associated documentation files (the "Software"), to deal
228
+ in the Software without restriction, including without limitation the rights
229
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
230
+ copies of the Software, and to permit persons to whom the Software is
231
+ furnished to do so, subject to the following conditions:
232
+
233
+ The above copyright notice and this permission notice shall be included in all
234
+ copies or substantial portions of the Software.
235
+
236
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
237
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
238
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
239
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
240
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
241
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
242
+ SOFTWARE.
243
+
244
+ See the ``LICENSE`` file in the repository root for the full license text,
245
+ or visit: https://github.com/mouhib-Sellami/django-keygen/blob/main/LICENSE
File without changes
@@ -0,0 +1,6 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class DjangoKeygenConfig(AppConfig):
5
+ default_auto_field = 'django.db.models.BigAutoField'
6
+ name = 'django_keygen'
File without changes
@@ -0,0 +1,38 @@
1
+ import string
2
+ import secrets
3
+
4
+
5
+ def generate_password(
6
+ length: int = 12,
7
+ use_uppercase: bool = False,
8
+ use_numbers: bool = False,
9
+ use_symbols: bool = False,
10
+ ) -> str:
11
+ """Generates a cryptographically secure random password based on specified constraints.
12
+
13
+ Args:
14
+ length (int, optional): The length of the generated password. Defaults to
15
+ 8.
16
+ use_uppercase (bool, optional): If True, includes uppercase letters (A-Z).
17
+ Defaults to False.
18
+ use_numbers (bool, optional): If True, includes numerical digits (0-9).
19
+ Defaults to False.
20
+ use_symbols (bool, optional): If True, includes punctuation/special
21
+ characters. Defaults to False.
22
+
23
+ Returns:
24
+ str: A randomly generated password string.
25
+
26
+ Example:
27
+ >>> generate_password(length=12, use_uppercase=True, use_numbers=True)
28
+ 'aB3k9P1zLxQ9'
29
+ """
30
+ content = string.ascii_lowercase
31
+ if use_uppercase:
32
+ content += string.ascii_uppercase
33
+ if use_symbols:
34
+ content += string.punctuation
35
+ if use_numbers:
36
+ content += string.digits
37
+
38
+ return "".join(secrets.choice(content) for i in range(length))
@@ -0,0 +1,176 @@
1
+ from pathlib import Path
2
+ from django.core.management.utils import get_random_secret_key
3
+ from django.core.management.base import BaseCommand
4
+ from django.conf import settings
5
+ from dotenv import dotenv_values
6
+
7
+
8
+ class Command(BaseCommand):
9
+ help = "Generate a secure secret key for Django and manage environment files."
10
+
11
+ env_content = """# Security Warning: keep the secret key used in production secret!
12
+ # This file was generated by django-env
13
+
14
+ """
15
+ env_generated_key_warning = "\n# This is managed by django-keygen"
16
+
17
+ def add_arguments(self, parser):
18
+ parser.add_argument(
19
+ "--append",
20
+ action="store_true",
21
+ help="Append or update the generated secret key in chosen environment files."
22
+ )
23
+
24
+ parser.add_argument(
25
+ "--no-input",
26
+ action="store_true",
27
+ help="Skip all interactive prompts and warnings automatically."
28
+ )
29
+
30
+ parser.add_argument(
31
+ "--file",
32
+ "-f",
33
+ type=str,
34
+ default=None,
35
+ help="Directly specify the name or path of an env file (skips interactive selection)."
36
+ )
37
+
38
+ def _append_to_env(self, generated_secret_key: str, env_files: list[str]):
39
+ for env in env_files:
40
+ env_path = Path(settings.BASE_DIR, env)
41
+ config = dotenv_values(env_path)
42
+
43
+ config['DJANGO_SECRET_KEY'] = generated_secret_key
44
+ self._write_to_env(config, env_path)
45
+
46
+ def _write_to_env(self, config: dict, env_file_path: Path):
47
+ content = self.env_content
48
+ for key, value in config.items():
49
+ if key == 'DJANGO_SECRET_KEY':
50
+ content += self.env_generated_key_warning + '\n'
51
+ content += f"{key}='{value}'\n"
52
+
53
+ with open(env_file_path, 'w') as f:
54
+ f.write(content)
55
+
56
+ def _select_env_file(self, no_input: bool = False) -> list[str]:
57
+ self.stdout.write(
58
+ "Searching for environment files (.env, .env.local, .env.production, etc.)...")
59
+
60
+ env_files = []
61
+ for file in Path(settings.BASE_DIR).rglob('*.env*'):
62
+ relative_path = file.relative_to(settings.BASE_DIR)
63
+ env_files.append(str(relative_path))
64
+
65
+ if not env_files:
66
+ self.stdout.write(self.style.WARNING(
67
+ "No environment files found to write to."))
68
+
69
+ self.stdout.write(
70
+ "Would you like to create a new '.env.local' file? [Y/n]: ", ending="")
71
+ if not no_input:
72
+ user_choice = input().strip().lower()
73
+ else:
74
+ user_choice = 'y'
75
+
76
+ if user_choice in ['y', 'yes', '']:
77
+ new_file = '.env.local'
78
+
79
+ new_file_path = Path(settings.BASE_DIR) / new_file
80
+ new_file_path.touch(exist_ok=True)
81
+
82
+ self.stdout.write(self.style.SUCCESS(
83
+ f"Created new file: {new_file}"))
84
+ return [new_file]
85
+ else:
86
+ self.stdout.write(self.style.WARNING(
87
+ "Operation cancelled. No files were updated."))
88
+ return []
89
+
90
+ self.stdout.write(self.style.WARNING(
91
+ "\n⚠️ WARNING: Modifying configuration files can alter or overwrite existing variables.\n"
92
+ "Ensure you have a backup of your secrets before continuing."
93
+ ))
94
+
95
+ self.stdout.write("\nSelect an environment file to update:")
96
+ self.stdout.write(f" 0 - Select all files ({len(env_files)} found)")
97
+ for idx, file_name in enumerate(env_files):
98
+ self.stdout.write(f" {idx + 1} - {file_name}")
99
+ if not no_input:
100
+ while True:
101
+ self.stdout.write("\nEnter selection number: ", ending="")
102
+ action = input().strip()
103
+
104
+ try:
105
+ action_number = int(action)
106
+ if action_number < 0 or action_number > len(env_files):
107
+ self.stdout.write(self.style.ERROR(
108
+ "Invalid selection. Number out of range."))
109
+ else:
110
+ if action_number == 0:
111
+ return env_files
112
+ return [env_files[action_number - 1]]
113
+ except ValueError:
114
+ self.stdout.write(self.style.ERROR(
115
+ "Invalid input. Please enter a valid integer number."))
116
+ else:
117
+ return env_files
118
+
119
+ def handle(self, *args, **options):
120
+ if settings.DEBUG:
121
+ self.stdout.write(self.style.WARNING(
122
+ "\n⚠️ SECURITY NOTICE: 'settings.DEBUG' is currently set to True.\n"
123
+ "Never run your Django application in a production environment with DEBUG enabled.\n"
124
+ ))
125
+
126
+ if options['append']:
127
+ self.stdout.write(self.style.WARNING(
128
+ "⚠️ IMPORTANT NOTICE:\n"
129
+ "Replacing an active server's SECRET_KEY will immediately invalidate all existing user sessions,\n"
130
+ "auth tokens, and signed cookies. If you only want to generate a text key without updating files,\n"
131
+ "abort this command and run it again without the '--append' flag.\n"
132
+ ))
133
+
134
+ self.stdout.write(
135
+ "Press [ENTER] to acknowledge this risk and continue, or Ctrl+C to abort...")
136
+ if not options['no_input']:
137
+ input()
138
+
139
+ self.stdout.write("Generating new secret key...")
140
+ secret_key = get_random_secret_key()
141
+
142
+ self.stdout.write(self.style.SUCCESS(
143
+ f"\nYour Secret Key: {secret_key}\n"))
144
+
145
+ if options['append']:
146
+ if options['file']:
147
+ target_file = options['file']
148
+ target_path = Path(settings.BASE_DIR) / target_file
149
+
150
+ if not target_path.exists():
151
+ self.stdout.write(self.style.WARNING(
152
+ f"File '{target_file}' does not exist. Creating it now."))
153
+ target_path.touch(exist_ok=True)
154
+
155
+ selected_files = [target_file]
156
+ else:
157
+ selected_files = self._select_env_file(no_input=options['no_input'])
158
+
159
+ if selected_files:
160
+ self._append_to_env(secret_key, selected_files)
161
+ self.stdout.write(self.style.SUCCESS(
162
+ f"Successfully updated files: {', '.join(selected_files)}"))
163
+ else:
164
+ self.stdout.write(self.style.WARNING(
165
+ "No updates were made to files."))
166
+ else:
167
+ self.stdout.write(self.style.SUCCESS("Successfully generated!"))
168
+
169
+ self.stdout.write(self.style.SUCCESS(
170
+ "\n"
171
+ "Action Required: Update your settings.py \n"
172
+ "--------------------------------------------------\n"
173
+ "To make Django read your newly generated key, use:\n\n"
174
+ "SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')\n"
175
+ "--------------------------------------------------"
176
+ ))
@@ -0,0 +1,94 @@
1
+ import sys
2
+ from django.core.management.base import BaseCommand
3
+ from django_keygen.core.passwords import generate_password
4
+
5
+
6
+ class Command(BaseCommand):
7
+ help = "Interactively generate highly secure, random passwords."
8
+
9
+ def add_arguments(self, parser):
10
+ parser.add_argument(
11
+ "--symbol",
12
+ action="store_true",
13
+ help="Include symbols/punctuation in the generated password.",
14
+ )
15
+ parser.add_argument(
16
+ "--numbers",
17
+ action="store_true",
18
+ help="Include numerical digits (0-9) in the generated password.",
19
+ )
20
+ parser.add_argument(
21
+ "--letters",
22
+ action="store_true",
23
+ help="Include lowercase letters (a-z) in the generated password.",
24
+ )
25
+ parser.add_argument(
26
+ "--uppercase",
27
+ action="store_true",
28
+ help="Include uppercase letters (A-Z) in the generated password.",
29
+ )
30
+ parser.add_argument(
31
+ "--secure",
32
+ action="store_true",
33
+ help="Shortcut to force uppercase, numbers, symbols, and a length of 20.",
34
+ )
35
+ parser.add_argument(
36
+ "--length",
37
+ "-len",
38
+ type=int,
39
+ default=12,
40
+ help="The length of the generated password (default: 12).",
41
+ )
42
+
43
+ def handle(self, *args, **options):
44
+ use_uppercase = True if options["secure"] else options["uppercase"]
45
+ use_symbols = True if options["secure"] else options["symbol"]
46
+ use_numbers = True if options["secure"] else options["numbers"]
47
+ length = options["length"]
48
+
49
+ while True:
50
+ password = generate_password(
51
+ length=length,
52
+ use_numbers=use_numbers,
53
+ use_symbols=use_symbols,
54
+ use_uppercase=use_uppercase,
55
+ )
56
+
57
+ self.stdout.write("\n" + "=" * 40)
58
+ self.stdout.write(
59
+ self.style.SUCCESS(f"Generated Password: {password}")
60
+ )
61
+ self.stdout.write("=" * 40 + "\n")
62
+
63
+ regen = (
64
+ input("Regenerate a new password? (y/N): ").strip().lower()
65
+ )
66
+ if regen != "y":
67
+ self.stdout.write(self.style.SUCCESS("Exiting."))
68
+ break
69
+
70
+ modify_config = (
71
+ input("Modify password configurations? (y/N): ")
72
+ .strip()
73
+ .lower()
74
+ )
75
+ if modify_config == "y":
76
+ action = input("Use symbols? (y/N): ").strip().lower()
77
+ use_symbols = action == "y"
78
+
79
+ action = input("Use numbers? (y/N): ").strip().lower()
80
+ use_numbers = action == "y"
81
+
82
+ action = input("Use uppercase? (y/N): ").strip().lower()
83
+ use_uppercase = action == "y"
84
+
85
+ try:
86
+ len_input = input(f"Password length ({length}): ").strip()
87
+ if len_input:
88
+ length = int(len_input)
89
+ except ValueError:
90
+ self.stdout.write(
91
+ self.style.WARNING(
92
+ f"Invalid number. Keeping current length of {length}."
93
+ )
94
+ )
@@ -0,0 +1,140 @@
1
+ from pathlib import Path
2
+ from django.core.management.utils import get_random_secret_key
3
+ from django.core.management.base import BaseCommand
4
+ from django.conf import settings
5
+ from dotenv import set_key, dotenv_values
6
+ from django_keygen.core.passwords import generate_password
7
+
8
+
9
+ class Command(BaseCommand):
10
+ help = "Generate secret keys or passwords into an environment file."
11
+
12
+ def add_arguments(self, parser):
13
+ parser.add_argument(
14
+ "secret",
15
+ nargs="*",
16
+ metavar="SECRET",
17
+ help="One or more variable names to generate a Django secret key for.",
18
+ )
19
+ parser.add_argument(
20
+ "--passwords",
21
+ "-p",
22
+ nargs="+",
23
+ metavar="PASSWORDS",
24
+ default=[],
25
+ help="One or more variable names to generate a secure password for.",
26
+ )
27
+ parser.add_argument(
28
+ "--file", "-f",
29
+ type=str,
30
+ default=".env",
31
+ help="Path to the env file relative to BASE_DIR (default: .env).",
32
+ )
33
+ parser.add_argument(
34
+ "--append",
35
+ action="store_true",
36
+ help="Append/update keys into the existing file instead of recreating it.",
37
+ )
38
+ parser.add_argument(
39
+ "--no-input",
40
+ action="store_true",
41
+ help="Skip all confirmation prompts.",
42
+ )
43
+
44
+ def _affix(self, value: str, options: dict) -> str:
45
+ prefix = options.get("prefix") or ""
46
+ suffix = options.get("suffix") or ""
47
+ return f"{prefix}{value}{suffix}"
48
+
49
+ def _resolve_file(self, options: dict) -> Path | None:
50
+ env_path = Path(settings.BASE_DIR) / options["file"]
51
+
52
+ if not env_path.exists():
53
+ if not options["no_input"]:
54
+ self.stdout.write(
55
+ self.style.WARNING(
56
+ f"'{options['file']}' does not exist. Create it? [Y/n]: "),
57
+ ending="",
58
+ )
59
+ if input().strip().lower() not in ("y", "yes", ""):
60
+ self.stdout.write(self.style.ERROR("Aborted."))
61
+ return None
62
+ env_path.touch()
63
+ self.stdout.write(self.style.SUCCESS(f"Created {options['file']}"))
64
+
65
+ if not options["append"] and not options["no_input"]:
66
+ self.stdout.write(self.style.WARNING(
67
+ f"\n⚠️ '{options['file']}' will be recreated and all existing values overwritten.\n"
68
+ "Press [ENTER] to continue or Ctrl+C to abort..."
69
+ ))
70
+ input()
71
+
72
+ return env_path
73
+
74
+ def _write_all(self, env_path: Path, secrets: dict[str, str]):
75
+ existing = dict(dotenv_values(env_path)) if env_path.exists() else {}
76
+ existing.update(secrets)
77
+ lines = "# Security Warning: keep the secret key used in production secret!\n"
78
+ lines += "# This file was managed/generated by django-keygen\n\n"
79
+ for key, value in existing.items():
80
+ lines += "\n# This secret was managed/generated by django-keygen\n"
81
+ lines += f"{key}='{value}'\n"
82
+ env_path.write_text(lines)
83
+
84
+ def handle(self, *args, **options):
85
+ if settings.DEBUG:
86
+ self.stdout.write(self.style.WARNING(
87
+ "\n⚠️ SECURITY NOTICE: 'settings.DEBUG' is currently set to True.\n"
88
+ "Never run your Django application in a production environment with DEBUG enabled.\n"
89
+ ))
90
+
91
+ if options['append']:
92
+ self.stdout.write(self.style.WARNING(
93
+ "⚠️ IMPORTANT NOTICE:\n"
94
+ "Replacing an active server's SECRET_KEY will immediately invalidate all existing user sessions,\n"
95
+ "auth tokens, and signed cookies. If you only want to generate a text key without updating files,\n"
96
+ "abort this command and run it again without the '--append' flag.\n"
97
+ ))
98
+
99
+ self.stdout.write(
100
+ "Press [ENTER] to acknowledge this risk and continue, or Ctrl+C to abort...")
101
+ if not options['no_input']:
102
+ input()
103
+ secret_names: list[str] = options["secret"]
104
+ passwords_names: list[str] = options["passwords"]
105
+ print(passwords_names)
106
+ if not secret_names and not passwords_names:
107
+ self.stdout.write(self.style.ERROR(
108
+ "Provide at least one variable name.\n"
109
+ " Secrets: python manage.py keygen KEY1 KEY2\n"
110
+ " Passwords: python manage.py keygen --passwords PASS1 PASS2\n"
111
+ " Mixed: python manage.py keygen KEY1 --passwords PASS1 --file .env.local"
112
+ ))
113
+ return
114
+
115
+ env_path = self._resolve_file(options)
116
+ if env_path is None:
117
+ return
118
+
119
+ generated: dict[str, str] = {}
120
+
121
+ for name in secret_names:
122
+ generated[name] = self._affix(get_random_secret_key(), options)
123
+
124
+ for name in passwords_names:
125
+ generated[name] = self._affix(generate_password(), options)
126
+
127
+ if options["append"]:
128
+ for key, value in generated.items():
129
+ set_key(env_path, key, value)
130
+ else:
131
+ self._write_all(env_path, generated)
132
+
133
+ self.stdout.write(self.style.MIGRATE_HEADING(
134
+ f"\n--- {options['file']} ---"))
135
+ for key, value in generated.items():
136
+ self.stdout.write(f" {self.style.MIGRATE_LABEL(key)}='{value}'")
137
+
138
+ self.stdout.write(self.style.SUCCESS(
139
+ f"\n {len(generated)} value(s) written to {options['file']}"
140
+ ))
@@ -0,0 +1,270 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-keygen
3
+ Version: 0.1.0
4
+ Summary: django-keygen is a Django management command utility designed to securely generate cryptographic secret keys.
5
+ Author-email: Mouhib sellami <mouhib.sellami@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/mouhib-Sellami/django-keygen
8
+ Classifier: Environment :: Web Environment
9
+ Classifier: Framework :: Django
10
+ Classifier: Framework :: Django :: 4.2
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Requires-Python: >=3.9
20
+ Description-Content-Type: text/x-rst
21
+ License-File: LICENSE
22
+ Requires-Dist: django>=4.2
23
+ Requires-Dist: python-dotenv>=1.0.0
24
+ Dynamic: license-file
25
+
26
+ django-keygen
27
+ =============
28
+
29
+ django-keygen is a Django management command utility for securely generating
30
+ cryptographic secret keys and passwords, and optionally writing them into your
31
+ project's environment (``.env``) files automatically.
32
+
33
+ Detailed documentation will be available in the "docs" directory.
34
+
35
+ Installation
36
+ ------------
37
+
38
+ Install via pip::
39
+
40
+ pip install django-keygen
41
+
42
+ Or install the latest version directly from GitHub::
43
+
44
+ pip install git+https://github.com/mouhib-Sellami/django-keygen.git
45
+
46
+ Quick start
47
+ -----------
48
+
49
+ 1. Add ``django_keygen`` to your ``INSTALLED_APPS``::
50
+
51
+ INSTALLED_APPS = [
52
+ ...,
53
+ 'django_keygen',
54
+ ]
55
+
56
+ Commands Overview
57
+ -----------------
58
+
59
+ django-keygen provides three management commands:
60
+
61
+ +---------------------------+-------------------------------------------------------+
62
+ | Command | Purpose |
63
+ +===========================+=======================================================+
64
+ | ``keygen`` | Generate secret keys and/or passwords into a named |
65
+ | | ``.env`` file. The recommended all-in-one command. |
66
+ +---------------------------+-------------------------------------------------------+
67
+ | ``generate_django_secret``| Dedicated command for generating a single |
68
+ | | ``DJANGO_SECRET_KEY`` and optionally writing it to |
69
+ | | an env file via an interactive or flag-driven flow. |
70
+ +---------------------------+-------------------------------------------------------+
71
+ | ``generate_password`` | Interactive terminal interface for generating and |
72
+ | | tweaking secure passwords. |
73
+ +---------------------------+-------------------------------------------------------+
74
+
75
+ ----
76
+
77
+ 1. ``keygen`` — Unified Key & Password Generator
78
+ -------------------------------------------------
79
+
80
+ The ``keygen`` command is the recommended way to generate one or more secret
81
+ keys and/or passwords and write them into an environment file in a single step.
82
+ Variable names are passed directly as arguments, so each generated value is
83
+ stored under the name you choose.
84
+
85
+ **Positional arguments:**
86
+
87
+ * ``SECRET [SECRET ...]``
88
+ One or more variable names to generate a Django secret key for (e.g.
89
+ ``SECRET_KEY API_KEY``). Each name receives its own independently generated
90
+ cryptographic key.
91
+
92
+ **Flags:**
93
+
94
+ * ``--passwords PASSWORDS [PASSWORDS ...]``, ``-p``
95
+ One or more variable names to generate a secure password for instead of a
96
+ Django secret key (e.g. ``-p DB_PASSWORD REDIS_PASSWORD``).
97
+
98
+ * ``--file FILE``, ``-f``
99
+ Path to the env file, relative to ``BASE_DIR`` (default: ``.env``). If the
100
+ file does not exist, the command offers to create it.
101
+
102
+ * ``--append``
103
+ Update the existing file in place rather than recreating it from scratch.
104
+ Without this flag the file is fully rewritten (all previous content is
105
+ preserved but reformatted alongside the new values). Prompts a confirmation
106
+ warning because replacing an active ``SECRET_KEY`` invalidates all existing
107
+ sessions, tokens, and signed cookies.
108
+
109
+ * ``--no-input``
110
+ Skip all confirmation prompts. Useful for automated deployments, Docker
111
+ entrypoints, and CI/CD pipelines.
112
+
113
+ **Examples**::
114
+
115
+ # Generate SECRET_KEY and write it to .env (recreates the file)
116
+ python manage.py keygen SECRET_KEY
117
+
118
+ # Generate two secret keys into a specific file, no prompts
119
+ python manage.py keygen SECRET_KEY API_KEY --file .env.production --no-input
120
+
121
+ # Generate a secret key and two passwords into .env.local, appending
122
+ python manage.py keygen SECRET_KEY --passwords DB_PASSWORD REDIS_PASSWORD \
123
+ --file .env.local --append
124
+
125
+ # Generate only passwords (no secret keys)
126
+ python manage.py keygen --passwords DB_PASSWORD --file .env
127
+
128
+ ----
129
+
130
+ 2. ``generate_django_secret`` — Dedicated Secret Key Command
131
+ -------------------------------------------------------------
132
+
133
+ The ``generate_django_secret`` command is dedicated to generating a single
134
+ Django secret key stored under the ``DJANGO_SECRET_KEY`` variable. Run it
135
+ without any flags to simply print a key to the terminal, or add ``--append``
136
+ to write it to an env file.
137
+
138
+ When writing to a file, the command either accepts a path via ``--file`` or
139
+ launches an interactive file-selection menu that scans your project for
140
+ existing ``.env*`` files.
141
+
142
+ **Flags:**
143
+
144
+ * ``--append``
145
+ Write the generated key to an environment file. Without this flag the key
146
+ is only printed to stdout — no files are touched. Prompts a confirmation
147
+ warning because replacing a live ``SECRET_KEY`` invalidates all existing
148
+ sessions, tokens, and signed cookies.
149
+
150
+ * ``--file FILE``, ``-f``
151
+ Directly specify the env file to update (e.g. ``-f .env.production``),
152
+ bypassing the interactive selection menu. If the file does not exist it is
153
+ created automatically. Only used together with ``--append``.
154
+
155
+ * ``--no-input``
156
+ Suppress all interactive prompts, menus, and risk warnings. Useful for
157
+ automated deployments and CI/CD pipelines.
158
+
159
+ **Examples**::
160
+
161
+ # Print a new secret key to the terminal only (no file changes)
162
+ python manage.py generate_django_secret
163
+
164
+ # Interactively choose which env file to update
165
+ python manage.py generate_django_secret --append
166
+
167
+ # Write directly to a specific file, no prompts
168
+ python manage.py generate_django_secret --append --no-input -f .env.local
169
+
170
+ **After running**, update your ``settings.py`` to read the key from the
171
+ environment::
172
+
173
+ import os
174
+ SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
175
+
176
+ ----
177
+
178
+ 3. ``generate_password`` — Interactive Password Generator
179
+ ---------------------------------------------------------
180
+
181
+ The ``generate_password`` command launches an interactive terminal session for
182
+ generating and refining secure passwords. After each password is shown, you can
183
+ regenerate it or adjust the composition settings without restarting the command.
184
+
185
+ **Flags** (set initial defaults; all can be changed interactively):
186
+
187
+ * ``--length LENGTH``, ``-len``
188
+ Desired password length (default: 12).
189
+
190
+ * ``--letters``
191
+ Include lowercase letters (a–z).
192
+
193
+ * ``--uppercase``
194
+ Include uppercase letters (A–Z).
195
+
196
+ * ``--numbers``
197
+ Include numerical digits (0–9).
198
+
199
+ * ``--symbol``
200
+ Include symbols and punctuation characters.
201
+
202
+ * ``--secure``
203
+ Shortcut that forces uppercase letters, numbers, symbols, and a minimum
204
+ length of 20. Overrides individual composition flags.
205
+
206
+ **Examples**::
207
+
208
+ # Launch with defaults (12 characters, no composition constraints)
209
+ python manage.py generate_password
210
+
211
+ # Start with a longer length and reconfigure interactively
212
+ python manage.py generate_password --length 16
213
+
214
+ # Instantly generate a highly secure 20-character password
215
+ python manage.py generate_password --secure
216
+
217
+ ----
218
+
219
+ Programmatic Usage
220
+ ------------------
221
+
222
+ The underlying password generator can be imported directly into your own
223
+ Django apps — useful for custom registration flows, invitation tokens, or
224
+ background tasks::
225
+
226
+ from django_keygen.core.passwords import generate_password
227
+
228
+ # Generate a secure password with specific character sets
229
+ new_password = generate_password(
230
+ length=14,
231
+ use_uppercase=True,
232
+ use_numbers=True,
233
+ use_symbols=True,
234
+ )
235
+
236
+ # Use it in your application logic
237
+ from django.contrib.auth.models import User
238
+ user = User.objects.create_user(username='johndoe', email='john@example.com')
239
+ user.set_password(new_password)
240
+ user.save()
241
+
242
+ ----
243
+
244
+ License
245
+ -------
246
+
247
+ django-keygen is released under the **MIT License**.
248
+
249
+ Copyright (c) 2026 Mouhib Sellami
250
+
251
+ Permission is hereby granted, free of charge, to any person obtaining a copy
252
+ of this software and associated documentation files (the "Software"), to deal
253
+ in the Software without restriction, including without limitation the rights
254
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
255
+ copies of the Software, and to permit persons to whom the Software is
256
+ furnished to do so, subject to the following conditions:
257
+
258
+ The above copyright notice and this permission notice shall be included in all
259
+ copies or substantial portions of the Software.
260
+
261
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
262
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
263
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
264
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
265
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
266
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
267
+ SOFTWARE.
268
+
269
+ See the ``LICENSE`` file in the repository root for the full license text,
270
+ or visit: https://github.com/mouhib-Sellami/django-keygen/blob/main/LICENSE
@@ -0,0 +1,18 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.rst
4
+ pyproject.toml
5
+ django_keygen/__init__.py
6
+ django_keygen/apps.py
7
+ django_keygen.egg-info/PKG-INFO
8
+ django_keygen.egg-info/SOURCES.txt
9
+ django_keygen.egg-info/dependency_links.txt
10
+ django_keygen.egg-info/requires.txt
11
+ django_keygen.egg-info/top_level.txt
12
+ django_keygen/core/__init__.py
13
+ django_keygen/core/passwords/__init__.py
14
+ django_keygen/management/__init__.py
15
+ django_keygen/management/commands/__init__.py
16
+ django_keygen/management/commands/generate_django_secret.py
17
+ django_keygen/management/commands/generate_password.py
18
+ django_keygen/management/commands/keygen.py
@@ -0,0 +1,2 @@
1
+ django>=4.2
2
+ python-dotenv>=1.0.0
@@ -0,0 +1 @@
1
+ django_keygen
@@ -0,0 +1,38 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77.0.3"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [tool.setuptools.packages.find]
6
+ where = ["."]
7
+ include = ["django_keygen*"]
8
+
9
+ [project]
10
+ name = "django-keygen"
11
+ version = "0.1.0"
12
+ dependencies = [
13
+ "django>=4.2",
14
+ "python-dotenv>=1.0.0",
15
+ ]
16
+ description = "django-keygen is a Django management command utility designed to securely generate cryptographic secret keys."
17
+ readme = "README.rst"
18
+ license = "MIT"
19
+ requires-python = ">= 3.9"
20
+ authors = [
21
+ {name = "Mouhib sellami", email = "mouhib.sellami@gmail.com"},
22
+ ]
23
+ classifiers = [
24
+ "Environment :: Web Environment",
25
+ "Framework :: Django",
26
+ "Framework :: Django :: 4.2",
27
+ "Intended Audience :: Developers",
28
+ "Operating System :: OS Independent",
29
+ "Programming Language :: Python",
30
+ "Programming Language :: Python :: 3",
31
+ "Programming Language :: Python :: 3 :: Only",
32
+ "Programming Language :: Python :: 3.12",
33
+ "Programming Language :: Python :: 3.13",
34
+ "Programming Language :: Python :: 3.14"
35
+ ]
36
+
37
+ [project.urls]
38
+ Homepage = "https://github.com/mouhib-Sellami/django-keygen"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+