Merge branch 'smf-2.1-compatibility' into 'v3.x'

SMF 2.1 compatibility

See merge request allianceauth/allianceauth!1432
This commit is contained in:
Ariel Rin 2022-07-07 07:35:58 +00:00
commit ff88a16163

View File

@ -6,6 +6,8 @@ import hashlib
import logging import logging
import re import re
from packaging import version
from django.db import connections from django.db import connections
from django.conf import settings from django.conf import settings
from allianceauth.eveonline.models import EveCharacter from allianceauth.eveonline.models import EveCharacter
@ -20,9 +22,18 @@ class SmfManager:
def __init__(self): def __init__(self):
pass pass
SQL_ADD_USER = r"INSERT INTO %smembers (member_name, passwd, email_address, date_registered, real_name," \ # For SMF < 2.1
r" buddy_list, message_labels, openid_uri, signature, ignore_boards) " \ SQL_ADD_USER_SMF_20 = r"INSERT INTO %smembers (member_name, passwd, email_address, date_registered, real_name," \
r"VALUES (%%s, %%s, %%s, %%s, %%s, 0, 0, 0, 0, 0)" % TABLE_PREFIX r" buddy_list, message_labels, openid_uri, signature, ignore_boards) " \
r"VALUES (%%s, %%s, %%s, %%s, %%s, 0, 0, 0, 0, 0)" % TABLE_PREFIX
# For SMF >= 2.1
SQL_ADD_USER_SMF_21 = r"INSERT INTO %smembers (member_name, passwd, email_address, date_registered, real_name," \
r" buddy_list, signature, ignore_boards) " \
r"VALUES (%%s, %%s, %%s, %%s, %%s, 0, 0, 0)" % TABLE_PREFIX
# returns something like »window.smfVersion = "SMF 2.0.19";«
SQL_GET_CURRENT_SMF_VERSION = r"SELECT data FROM %sadmin_info_files WHERE filename = %%s" % TABLE_PREFIX
SQL_DEL_USER = r"DELETE FROM %smembers where member_name = %%s" % TABLE_PREFIX SQL_DEL_USER = r"DELETE FROM %smembers where member_name = %%s" % TABLE_PREFIX
@ -46,6 +57,26 @@ class SmfManager:
SQL_ADD_USER_AVATAR = r"UPDATE %smembers SET avatar = %%s WHERE id_member = %%s" % TABLE_PREFIX SQL_ADD_USER_AVATAR = r"UPDATE %smembers SET avatar = %%s WHERE id_member = %%s" % TABLE_PREFIX
@classmethod
def _get_current_smf_version(cls) -> str:
"""
Get the current SMF version from the DB
:return:
"""
cursor = connections['smf'].cursor()
cursor.execute(cls.SQL_GET_CURRENT_SMF_VERSION, ['current-version.js'])
row = cursor.fetchone()
db_result = row[0]
pattern = re.compile(r"\d+(\.\d+)+")
result = pattern.search(db_result)
smf_version = result.group(0)
return smf_version
@staticmethod @staticmethod
def _sanitize_groupname(name): def _sanitize_groupname(name):
name = name.strip(' _') name = name.strip(' _')
@ -73,15 +104,15 @@ class SmfManager:
@classmethod @classmethod
def create_group(cls, groupname): def create_group(cls, groupname):
logger.debug("Creating smf group %s" % groupname) logger.debug(f"Creating smf group {groupname}")
cursor = connections['smf'].cursor() cursor = connections['smf'].cursor()
cursor.execute(cls.SQL_ADD_GROUP, [groupname, groupname]) cursor.execute(cls.SQL_ADD_GROUP, [groupname, groupname])
logger.info("Created smf group %s" % groupname) logger.info(f"Created smf group {groupname}")
return cls.get_group_id(groupname) return cls.get_group_id(groupname)
@classmethod @classmethod
def get_group_id(cls, groupname): def get_group_id(cls, groupname):
logger.debug("Getting smf group id for groupname %s" % groupname) logger.debug(f"Getting smf group id for groupname {groupname}")
cursor = connections['smf'].cursor() cursor = connections['smf'].cursor()
cursor.execute(cls.SQL_GET_GROUP_ID, [groupname]) cursor.execute(cls.SQL_GET_GROUP_ID, [groupname])
row = cursor.fetchone() row = cursor.fetchone()
@ -90,14 +121,14 @@ class SmfManager:
@classmethod @classmethod
def check_user(cls, username): def check_user(cls, username):
logger.debug("Checking smf username %s" % username) logger.debug(f"Checking smf username {username}")
cursor = connections['smf'].cursor() cursor = connections['smf'].cursor()
cursor.execute(cls.SQL_USER_ID_FROM_USERNAME, [cls.santatize_username(username)]) cursor.execute(cls.SQL_USER_ID_FROM_USERNAME, [cls.santatize_username(username)])
row = cursor.fetchone() row = cursor.fetchone()
if row: if row:
logger.debug("Found user %s on smf" % username) logger.debug(f"Found user {username} on smf")
return True return True
logger.debug("User %s not found on smf" % username) logger.debug(f"User {username} not found on smf")
return False return False
@classmethod @classmethod
@ -110,7 +141,7 @@ class SmfManager:
@classmethod @classmethod
def get_user_id(cls, username): def get_user_id(cls, username):
logger.debug("Getting smf user id for username %s" % username) logger.debug(f"Getting smf user id for username {username}")
cursor = connections['smf'].cursor() cursor = connections['smf'].cursor()
cursor.execute(cls.SQL_USER_ID_FROM_USERNAME, [username]) cursor.execute(cls.SQL_USER_ID_FROM_USERNAME, [username])
row = cursor.fetchone() row = cursor.fetchone()
@ -118,7 +149,7 @@ class SmfManager:
logger.debug(f"Got smf user id {row[0]} for username {username}") logger.debug(f"Got smf user id {row[0]} for username {username}")
return row[0] return row[0]
else: else:
logger.error("username %s not found on smf. Unable to determine user id ." % username) logger.error(f"username {username} not found on smf. Unable to determine user id .")
return None return None
@classmethod @classmethod
@ -130,12 +161,12 @@ class SmfManager:
out = {} out = {}
for row in rows: for row in rows:
out[row[1]] = row[0] out[row[1]] = row[0]
logger.debug("Got smf groups %s" % out) logger.debug(f"Got smf groups {out}")
return out return out
@classmethod @classmethod
def get_user_groups(cls, userid): def get_user_groups(cls, userid):
logger.debug("Getting smf user id %s groups" % userid) logger.debug(f"Getting smf user id {userid} groups")
cursor = connections['smf'].cursor() cursor = connections['smf'].cursor()
cursor.execute(cls.SQL_GET_USER_GROUPS, [userid]) cursor.execute(cls.SQL_GET_USER_GROUPS, [userid])
out = [row[0] for row in cursor.fetchall()] out = [row[0] for row in cursor.fetchall()]
@ -144,8 +175,11 @@ class SmfManager:
@classmethod @classmethod
def add_user(cls, username, email_address, groups, characterid): def add_user(cls, username, email_address, groups, characterid):
logger.debug("Adding smf user with member_name {}, email_address {}, characterid {}".format( logger.debug(
username, email_address, characterid)) f"Adding smf user with member_name {username}, "
f"email_address {email_address}, "
f"characterid {characterid}"
)
cursor = connections['smf'].cursor() cursor = connections['smf'].cursor()
username_clean = cls.santatize_username(username) username_clean = cls.santatize_username(username)
passwd = cls.generate_random_pass() passwd = cls.generate_random_pass()
@ -154,42 +188,59 @@ class SmfManager:
register_date = cls.get_current_utc_date() register_date = cls.get_current_utc_date()
# check if the username was simply revoked # check if the username was simply revoked
if cls.check_user(username) is True: if cls.check_user(username) is True:
logger.warn("Unable to add smf user with username %s - already exists. Updating user instead." % username) logger.warning(f"Unable to add smf user with username {username} - already exists. Updating user instead.")
cls.__update_user_info(username_clean, email_address, pwhash) cls.__update_user_info(username_clean, email_address, pwhash)
else: else:
try: try:
cursor.execute(cls.SQL_ADD_USER, smf_version = cls._get_current_smf_version()
[username_clean, passwd, email_address, register_date, username_clean])
if version.parse(smf_version) < version.parse("2.1"):
logger.debug("SMF compatibility: < 2.1")
cursor.execute(
cls.SQL_ADD_USER_SMF_20,
[username_clean, pwhash, email_address, register_date, username_clean]
)
else:
logger.debug("SMF compatibility: >= 2.1")
cursor.execute(
cls.SQL_ADD_USER_SMF_21,
[username_clean, pwhash, email_address, register_date, username_clean]
)
cls.add_avatar(username_clean, characterid) cls.add_avatar(username_clean, characterid)
logger.info("Added smf member_name %s" % username_clean) logger.info(f"Added smf member_name {username_clean}")
cls.update_groups(username_clean, groups) cls.update_groups(username_clean, groups)
except: except Exception as e:
logger.warn("Unable to add smf user %s" % username_clean) logger.warning(f"Unable to add smf user {username_clean}: {e}")
pass pass
return username_clean, passwd return username_clean, passwd
@classmethod @classmethod
def __update_user_info(cls, username, email_address, passwd): def __update_user_info(cls, username, email_address, passwd):
logger.debug( logger.debug(
f"Updating smf user {username} info: username {email_address} password of length {len(passwd)}") f"Updating smf user {username} info: "
f"username {email_address} "
f"password of length {len(passwd)}"
)
cursor = connections['smf'].cursor() cursor = connections['smf'].cursor()
try: try:
cursor.execute(cls.SQL_DIS_USER, [email_address, passwd, username]) cursor.execute(cls.SQL_DIS_USER, [email_address, passwd, username])
logger.info("Updated smf user %s info" % username) logger.info(f"Updated smf user {username} info")
except: except Exception as e:
logger.exception("Unable to update smf user %s info." % username) logger.exception(f"Unable to update smf user {username} info. ({e})")
pass pass
@classmethod @classmethod
def delete_user(cls, username): def delete_user(cls, username):
logger.debug("Deleting smf user %s" % username) logger.debug(f"Deleting smf user {username}")
cursor = connections['smf'].cursor() cursor = connections['smf'].cursor()
if cls.check_user(username): if cls.check_user(username):
cursor.execute(cls.SQL_DEL_USER, [username]) cursor.execute(cls.SQL_DEL_USER, [username])
logger.info("Deleted smf user %s" % username) logger.info(f"Deleted smf user {username}")
return True return True
logger.error("Unable to delete smf user %s - user not found on smf." % username) logger.error(f"Unable to delete smf user {username} - user not found on smf.")
return False return False
@classmethod @classmethod
@ -218,8 +269,8 @@ class SmfManager:
cursor = connections['smf'].cursor() cursor = connections['smf'].cursor()
cursor.execute(cls.SQL_ADD_USER_GROUP, [groupid, userid]) cursor.execute(cls.SQL_ADD_USER_GROUP, [groupid, userid])
logger.info(f"Added smf user id {userid} to group id {groupid}") logger.info(f"Added smf user id {userid} to group id {groupid}")
except: except Exception as e:
logger.exception(f"Unable to add smf user id {userid} to group id {groupid}") logger.exception(f"Unable to add smf user id {userid} to group id {groupid} ({e})")
pass pass
@classmethod @classmethod
@ -229,13 +280,13 @@ class SmfManager:
cursor = connections['smf'].cursor() cursor = connections['smf'].cursor()
cursor.execute(cls.SQL_REMOVE_USER_GROUP, [groupid, userid]) cursor.execute(cls.SQL_REMOVE_USER_GROUP, [groupid, userid])
logger.info(f"Removed smf user id {userid} from group id {groupid}") logger.info(f"Removed smf user id {userid} from group id {groupid}")
except: except Exception as e:
logger.exception(f"Unable to remove smf user id {userid} from group id {groupid}") logger.exception(f"Unable to remove smf user id {userid} from group id {groupid} ({e})")
pass pass
@classmethod @classmethod
def disable_user(cls, username): def disable_user(cls, username):
logger.debug("Disabling smf user %s" % username) logger.debug(f"Disabling smf user {username}")
cursor = connections['smf'].cursor() cursor = connections['smf'].cursor()
password = cls.generate_random_pass() password = cls.generate_random_pass()
@ -245,15 +296,15 @@ class SmfManager:
cursor.execute(cls.SQL_DIS_USER, [revoke_email, pwhash, username]) cursor.execute(cls.SQL_DIS_USER, [revoke_email, pwhash, username])
cls.get_user_id(username) cls.get_user_id(username)
cls.update_groups(username, []) cls.update_groups(username, [])
logger.info("Disabled smf user %s" % username) logger.info(f"Disabled smf user {username}")
return True return True
except TypeError: except TypeError:
logger.exception("TypeError occured while disabling user %s - failed to disable." % username) logger.exception(f"TypeError occured while disabling user {username} - failed to disable.")
return False return False
@classmethod @classmethod
def update_user_password(cls, username, characterid, password=None): def update_user_password(cls, username, characterid, password=None):
logger.debug("Updating smf user %s password" % username) logger.debug(f"Updating smf user {username} password")
cursor = connections['smf'].cursor() cursor = connections['smf'].cursor()
if not password: if not password:
password = cls.generate_random_pass() password = cls.generate_random_pass()
@ -261,10 +312,12 @@ class SmfManager:
username_clean = cls.santatize_username(username) username_clean = cls.santatize_username(username)
pwhash = cls.gen_hash(username_clean, password) pwhash = cls.gen_hash(username_clean, password)
logger.debug( logger.debug(
f"Proceeding to update smf user {username} password with pwhash starting with {pwhash[0:5]}") f"Proceeding to update smf user {username} "
f"password with pwhash starting with {pwhash[0:5]}"
)
cursor.execute(cls.SQL_UPDATE_USER_PASSWORD, [pwhash, username]) cursor.execute(cls.SQL_UPDATE_USER_PASSWORD, [pwhash, username])
cls.add_avatar(username, characterid) cls.add_avatar(username, characterid)
logger.info("Updated smf user %s password." % username) logger.info(f"Updated smf user {username} password.")
return password return password
logger.error("Unable to update smf user %s password - user not found on smf." % username) logger.error(f"Unable to update smf user {username} password - user not found on smf.")
return "" return ""