EnglishPal/app/Login.py

144 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import hashlib
import string
from datetime import datetime, timedelta
import unicodedata
# 使用固定盐值增强密码安全性
PASSWORD_SALT = "wordfreq_salt_2023"
def md5(s):
'''
MD5摘要
:param str: 字符串
:return: 经MD5以后的字符串
'''
h = hashlib.md5(s.encode(encoding='utf-8'))
return h.hexdigest()
# 延迟导入 model.user避免循环导入
path_prefix = '/var/www/wordfreq/wordfreq/'
path_prefix = './' # comment this line in deployment
def verify_user(username, password):
'''验证用户凭据'''
from model.user import get_user_by_username # 延迟导入
user = get_user_by_username(username)
if user is None:
return False
# 使用带盐值的加密
encrypted_password = md5(PASSWORD_SALT + username + password)
return user.password == encrypted_password
def add_user(username, password):
start_date = datetime.now().strftime('%Y%m%d')
expiry_date = (datetime.now() + timedelta(days=30)).strftime('%Y%m%d') # will expire after 30 days
# 使用带盐值的加密
encrypted_password = md5(PASSWORD_SALT + username + password)
from model.user import insert_user # 延迟导入
insert_user(
username=username,
password=encrypted_password,
start_date=start_date,
expiry_date=expiry_date
)
def check_username_availability(username):
# 延迟导入,避免循环导入
from model.user import get_user_by_username
return get_user_by_username(username) is None
def change_password(username, old_password, new_password):
'''
修改密码
:param username: 用户名
:param old_password: 旧的密码
:param new_password: 新密码
:return: 修改成功:True 否则:False
'''
if not verify_user(username, old_password): # 旧密码错误
return {'error':'Old password is wrong.', 'username':username}
# 将用户名和密码一起加密,以免暴露不同用户的相同密码
if new_password == old_password: #新旧密码一致
return {'error':'New password cannot be the same as the old password.', 'username':username}
# 加密新密码(修复了原代码未加密的安全漏洞)
encrypted_new_password = md5(PASSWORD_SALT + username + new_password)
# 延迟导入,避免循环导入
from model.user import update_password_by_username
update_password_by_username(username, encrypted_new_password)
return {'success': 'Password changed', 'username':username}
def get_expiry_date(username):
# 延迟导入,避免循环导入
from model.user import get_user_by_username
user = get_user_by_username(username)
return user.expiry_date if user else '20191024' # 默认过期日期
class UserName:
def __init__(self, username):
self.username = username
def contains_chinese(self):
for char in self.username:
# Check if the character is in the CJK (Chinese, Japanese, Korean) Unicode block
if unicodedata.name(char).startswith('CJK UNIFIED IDEOGRAPH'):
return True
return False
def validate(self):
if len(self.username) > 20:
return f'{self.username} is too long. The user name cannot exceed 20 characters.'
if self.username.startswith('.'): # a user name must not start with a dot
return 'Period (.) is not allowed as the first letter in the user name.'
if ' ' in self.username: # a user name must not include a whitespace
return 'Whitespace is not allowed in the user name.'
for c in self.username: # a user name must not include special characters, except non-leading periods or underscores
if c in string.punctuation and c != '.' and c != '_':
return f'{c} is not allowed in the user name.'
if self.username in ['signup', 'login', 'logout', 'reset', 'mark', 'back', 'unfamiliar', 'familiar', 'del',
'admin']:
return 'You used a restricted word as your user name. Please come up with a better one.'
if self.contains_chinese():
return 'Chinese characters are not allowed in the user name.'
return 'OK'
class Password:
'''密码验证类'''
def __init__(self, password):
self.password = password
def contains_cjk(self):
for char in self.password:
# Check if the character is in the CJK (Chinese, Japanese, Korean) Unicode block
if unicodedata.name(char).startswith('CJK UNIFIED IDEOGRAPH'):
return True
return False
def validate(self):
'''验证密码有效性'''
if len(self.password) < 6: # 提高最小长度要求
return 'Password must be at least 4 characters long.'
if ' ' in self.password:
return 'Password cannot contain spaces.'
if self.contains_cjk():
return 'Chinese characters are not allowed in the password.'
# 添加额外的安全检查
if not any(char.isdigit() for char in self.password):
return '密码应包含至少一个数字'
return 'OK'
class WarningMessage:
'''验证消息生成类'''
def __init__(self, input_str, input_type='username'):
self.input_str = input_str
self.input_type = input_type
def __str__(self):
if self.input_type == 'username':
return UserName(self.input_str).validate()
if self.input_type == 'password':
return Password(self.input_str).validate()
return '未知验证类型'