I am a system admin, not a developer, so this might be pretty horrible code. This is a password generator. The point of the attempt was to become more familiar with Django at a lower level. I current host Django sites other developers write and sometimes it would help to have a better understanding of how the sites work at a lower level. I realize a password generator should run client side not server side but a highly secure, strong password generator was not my primary concern in writing this. It just seemed like an appropriately sized problem to jump into this with.
Any feedback on either Python or Django best practices would be appreciated. The logic of the password generation is not my primary concern however I would be willing to hear any thoughts on that as well.
Since I am not using a database or any models I am sure I will be told some other framework is probably more appropriate but this was just an iterative step in learning Django. My next project will contain a database.
views.py
from django.http import HttpResponse
from django.shortcuts import render, render_to_response
from django.views import generic
import datetime
import random
import string
from .forms import PasswordGeneratorForm
def generate_password(request):
'''Generate a random password. Uses request POST data to allow user
to set length and character set.'''
pw_charset_lower = list(string.ascii_lowercase)
pw_charset_upper = list(string.ascii_uppercase)
pw_charset_digit = list(string.digits)
pw_charset_special = list(string.punctuation)
pw_charset_similar = ['o', 'O', '0', 'I', 'l', '1', '|']
if request.method == 'POST':
form = PasswordGeneratorForm(request.POST)
if form.is_valid():
pw_len = form.cleaned_data['length']
if request.POST.get('avoid_similar', False):
for x in pw_charset_similar:
if x in pw_charset_lower: pw_charset_lower.remove(x)
if x in pw_charset_upper: pw_charset_upper.remove(x)
if x in pw_charset_digit: pw_charset_digit.remove(x)
if x in pw_charset_special: pw_charset_special.remove(x)
charset = []
password = ""
if request.POST.get('use_upper', False):
charset = charset + pw_charset_upper
password = password + random.choice(pw_charset_upper)
if request.POST.get('use_lower', False):
charset = charset + pw_charset_lower
password = password + random.choice(pw_charset_lower)
if request.POST.get('use_digits', False):
charset = charset + pw_charset_digit
password = password + random.choice(pw_charset_digit)
if request.POST.get('use_special', False):
charset = charset + pw_charset_special
password = password + random.choice(pw_charset_special)
while pw_len > len(password):
password += random.choice(charset)
pw_list = list(password)
random.shuffle(pw_list)
pw_string = ''.join(pw_list)
else:
form = PasswordGeneratorForm()
pw_string = "Your password will show here"
pw_len = 12
return render(request, 'password/index.html', { 'password' : pw_string,
'length' : pw_len,
'form' : form})
forms.py
from django import forms
class PasswordGeneratorForm(forms.Form):
length = forms.IntegerField(min_value=4, max_value=128)
use_upper = forms.BooleanField(initial=True, required=False)
use_lower = forms.BooleanField(initial=True, required=False)
use_digits = forms.BooleanField(initial=True, required=False)
use_special = forms.BooleanField(initial=True, required=False)
avoid_similar = forms.BooleanField(initial=True, required=False)
index.html
{% load static %}
<link rel="stylesheet" type="text/css"
href="{% static 'password/style.css' %}" />
<html>
<head>
<title>Password Generator</title>
</head>
<body>
<form action="{% url 'password:index' %}" method="post">
{% csrf_token %}
<br>
<div id=password>
<output name="password" size="{{ length }}">{{ password }}</output>
</div>
<br>
<ul>
{{ form.as_ul }}
</ul>
<br>
<input type="submit" value="Generate New Password">
</form>
</body>
</html>
secrets
. If notos.urandom
orrandom.SystemRandom
. The Python standard library doesn't joke around with warnings, there are reasons they're there. \$\endgroup\$