Przeglądaj źródła

Merge branch 'minor' of sindre/Beelance into master

pull/38/head
Sindre Stephansen 5 lat temu
rodzic
commit
c10f4967cb
7 zmienionych plików z 111 dodań i 45 usunięć
  1. +2
    -2
      mysql/sql/init.sql
  2. +8
    -3
      src/Dockerfile
  3. +27
    -29
      src/app/models/user.py
  4. +1
    -0
      src/app/requirements.txt
  5. +3
    -5
      src/app/views/login.py
  6. +12
    -6
      src/app/views/register.py
  7. +58
    -0
      src/app/views/utils.py

+ 2
- 2
mysql/sql/init.sql Wyświetl plik

@@ -2,7 +2,7 @@
CREATE TABLE users (
userid INT UNSIGNED AUTO_INCREMENT,
username VARCHAR(45) UNIQUE NOT NULL,
password VARCHAR(45) NOT NULL,
password VARCHAR(60) NOT NULL,
full_name VARCHAR(200) NOT NULL,
company VARCHAR(50),
email VARCHAR(50) NOT NULL,
@@ -84,7 +84,7 @@ CREATE TABLE task_files (
* Initial data
*/

insert into users values (NULL, "admin", "48bead1bb864138c2cafaf1bd41332ab", "Admin Modsen", "ntnu", 'mail@ntnu.no', "street", "trondheim", "trondheim", "1234", "norway");
insert into users values (NULL, "admin", "$2b$12$iKbYZ0MFwWWxoYUXKRhFiOPo7itaQO2DIRnLgXbECsj8XKVzkNCSi", "Admin Modsen", "ntnu", 'mail@ntnu.no', "street", "trondheim", "trondheim", "1234", "norway");

insert into project_category values (NULL, "Gardening");
insert into project_category values (NULL, "Programming");


+ 8
- 3
src/Dockerfile Wyświetl plik

@@ -4,10 +4,11 @@ FROM tiangolo/uwsgi-nginx:python3.7
ENV LISTEN_PORT 8080
EXPOSE 8080

# Define environment
COPY ./app /app
RUN echo ${groupid} > /app/models/.env
WORKDIR /app

# The requirements file is copied first, so if there are no changes
# docker will skip installing them again, and use a cached image instead
COPY ./app/requirements.txt /app/
ENV PYTHONPATH=/app

# Install python dependencies
@@ -23,6 +24,10 @@ COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

# Copy the rest of the project files and define the environment
COPY ./app /app
RUN echo ${groupid} > /app/models/.env

# Allow waiting script to be executed
RUN chmod +x ./wait-for-it.sh



+ 27
- 29
src/app/models/user.py Wyświetl plik

@@ -2,6 +2,33 @@ from models.database import db
import mysql.connector


def get_user(username):
"""
Get the user with the given username

:param username: The username
:type username: str
:return: user
"""
db.connect()
cursor = db.cursor()
query = ("SELECT userid, username, password from users where username = %s")
user = None
try:
cursor.execute(query, (username,))
users = cursor.fetchall()
if len(users):
user = users[0]
except mysql.connector.Error as err:
print("Failed executing query: {}".format(err))
cursor.fetchall()
exit(1)
finally:
cursor.close()
db.close()
return user


def get_users():
"""
Retreive all registrered users from the database
@@ -73,32 +100,3 @@ def get_user_name_by_id(userid):
cursor.close()
db.close()
return username


def match_user(username, password):
"""
Check if user credentials are correct, return if exists

:param username: The user attempting to authenticate
:param password: The corresponding password
:type username: str
:type password: str
:return: user
"""
db.connect()
cursor = db.cursor()
query = ("SELECT userid, username from users where username = %s and password = %s")
user = None
try:
cursor.execute(query, (username, password))
users = cursor.fetchall()
if len(users):
user = users[0]
except mysql.connector.Error as err:
print("Failed executing query: {}".format(err))
cursor.fetchall()
exit(1)
finally:
cursor.close()
db.close()
return user

+ 1
- 0
src/app/requirements.txt Wyświetl plik

@@ -1,3 +1,4 @@
web.py==0.40
mysql-connector-python==8.0.*
python-dotenv
bcrypt

+ 3
- 5
src/app/views/login.py Wyświetl plik

@@ -5,7 +5,7 @@ import models.session
import models.user
import random
import string
import hashlib
import bcrypt
import time

# Get html templates
@@ -45,11 +45,9 @@ class Login():
data = web.input(username="", password="", remember=False)

# Validate login credential with database query
password_hash = hashlib.md5(b'TDT4237' + data.password.encode('utf-8')).hexdigest()
user = models.user.match_user(data.username, password_hash)
user = models.user.get_user(data.username)

# If there is a matching user/password in the database the user is logged in
if user:
if bcrypt.checkpw(data.password.encode('UTF-8'), user[2].encode('UTF-8')):
self.login(user[1], user[0], data.remember)
raise web.seeother("/")
else:


+ 12
- 6
src/app/views/register.py Wyświetl plik

@@ -1,9 +1,9 @@
import web
from views.forms import register_form
from views.utils import get_nav_bar, csrf_protected
from views.utils import get_nav_bar, csrf_protected, password_weakness
import models.register
import models.user
import hashlib
import bcrypt
import re

# Get html templates
@@ -41,9 +41,15 @@ class Register:
if models.user.get_user_id_by_name(data.username):
return render.register(nav, register, "Invalid user, already exists.")

models.register.set_user(data.username,
hashlib.md5(b'TDT4237' + data.password.encode('utf-8')).hexdigest(),
data.full_name, data.company, data.email, data.street_address,
data.city, data.state, data.postal_code, data.country)
# Check password security
weakness = password_weakness(data.password, data.username)
if weakness is not None:
return render.register(nav, register, weakness)

password_hash = bcrypt.hashpw(data.password.encode('UTF-8'), bcrypt.gensalt())

models.register.set_user(data.username, password_hash, data.full_name, data.company,
data.email, data.street_address, data.city, data.state,
data.postal_code, data.country)

return render.register(nav, register_form, "User registered!")

+ 58
- 0
src/app/views/utils.py Wyświetl plik

@@ -78,3 +78,61 @@ def csrf_protected(f):
return f(*args, **kwargs)

return decorated


def is_common_password(password):
"""Helper function that checks various common passwords."""
def common_sequences(n):
# Check sequences of the same number
for i in range(n):
for j in range(n):
yield ''.join([str(i) for _ in range(j)])

# Check incrementing sequences
for i in range(n):
# Starting at 0
seq = ''.join([str(j) for j in range(i)])
yield seq
# Starting at 1
yield seq[1:]

# Decrementing
# Starting at 0
yield seq[::-1]
# Starting at 1
yield seq[1::-1]

common_passwords = [
'password', 'qwerty', 'iloveyou', '123123', 'abc123', 'admin',
'passwrod', 'password1', 'beelance', 'beelance2'
]

if password in common_passwords or password in common_sequences(12):
return True

return False


def password_weakness(password, username):
"""
Check if the password fulfills the password policy.

The policy is:
- At least 8 characters, but not more than 70 (due to bcrypt)
- Does not overlap with the username
- Not a common password

:param password: The password to check
:param username: The username of the user (used to check similarity)
:return: The most important weakness of the password, or None if it fulfills the policy
"""
if len(password) < 8:
return "The password must be at least 5 characters long."
elif len(password) > 70:
return "The password can't be longer than 70 characters."
elif password in username or username in password:
return "The password can't overlap with your username."
elif is_common_password(password):
return "The password is too common. Choose something more unique."

return None

Ładowanie…
Anuluj
Zapisz