Skip to content

Commit

Permalink
fix #344
Browse files Browse the repository at this point in the history
DELETEACCOUNT username
  • Loading branch information
silentwings committed Apr 26, 2019
1 parent 0469084 commit 1caf080
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 45 deletions.
32 changes: 17 additions & 15 deletions SQLUsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ def check_banned(self, username, ip):
return True, reason
return False, ""

def login_user(self, username, password, ip, lobby_id, last_id, local_ip, country):
def check_login_user(self, username, password):
# password here is unicode(BASE64(MD5(...))), matches the register_user DB encoding
dbuser = self.sess().query(User).filter(User.username == username).first()
if (not dbuser):
Expand All @@ -527,8 +527,11 @@ def login_user(self, username, password, ip, lobby_id, last_id, local_ip, countr
return False, "Invalid username -- did you mean '%s'" % dbuser.username
if (not self.legacy_test_user_pwrd(dbuser, password)):
return False, 'Invalid username or password'

return True, ""

def login_user(self, username, password, ip, lobby_id, last_id, local_ip, country):
now = datetime.now()
dbuser = self.sess().query(User).filter(User.username == username).first()
dbuser.logins.append(Login(now, ip, lobby_id, last_id, local_ip, country))
dbuser.time = now
dbuser.last_ip = ip
Expand All @@ -544,12 +547,10 @@ def login_user(self, username, password, ip, lobby_id, last_id, local_ip, countr
user_copy.last_id = dbuser.last_id
user_copy.register_date = dbuser.register_date
user_copy.lobby_id = lobby_id
reason = user_copy

dbuser.last_login = now # store current time to db but keep last_login in the copy we send back
self.sess().commit()

return True, reason
return user_copy

def end_session(self, user_id):
entry = self.sess().query(User).filter(User.id==user_id).first()
Expand All @@ -573,11 +574,11 @@ def check_register_user(self, username, email=None, ip_address=None):
return False, reason
dbuser = self.sess().query(User).filter(User.username == username).first()
if dbuser:
return False, 'Username already exists.'
return False, 'Username is not available, please try another.'
if email:
dbemail = self.sess().query(User).filter(User.email == email).first()
if dbemail:
return False, 'Email address already in use.'
return False, 'Email address is already in use.'
if ip_address:
ipban = self._root.bandb.check_ban(None, ip_address)
if ipban:
Expand Down Expand Up @@ -625,7 +626,7 @@ def save_user(self, obj):
entry.email = obj.email

self.sess().commit()

def get_user_id_with_email(self, email):
if email == '':
return False, 'Email address is blank'
Expand Down Expand Up @@ -690,8 +691,8 @@ def clean(self):
logging.info("deleting %i users who failed to verify registration", response.count())
response.delete(synchronize_session=False)

# which have no ingame time, last login > 30 days, not bot, not mod
response = self.sess().query(User).filter(User.ingame_time == 0).filter(User.last_login < now - timedelta(days=30)).filter(User.bot == 0).filter(User.access == "user")
# which have no ingame time, last login > 1 month ago, not bot, not mod
response = self.sess().query(User).filter(User.ingame_time == 0).filter(User.last_login < now - timedelta(days=28)).filter(User.bot == 0).filter(User.access == "user")
logging.info("deleting %i inactive users with no ingame time", response.count())
response.delete(synchronize_session=False)

Expand Down Expand Up @@ -1218,7 +1219,7 @@ def clean(self):
response.delete(synchronize_session=False)
self.sess().commit()

def reset_password(self, user_id):
def reset_password(self, user_id, email_to_user):
# reset pw, email to user
char_set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!£$%^&*?"
new_password_raw = ""
Expand All @@ -1233,10 +1234,11 @@ def reset_password(self, user_id):
dbuser.password = new_password
self.sess().commit()

try:
thread.start_new_thread(self._send_reset_password_email, (dbuser.email, dbuser.username, new_password_raw,))
except:
logging.error('Failed to launch UserHandler._send_recover_account_email: %s' % (dbuser))
if email_to_user:
try:
thread.start_new_thread(self._send_reset_password_email, (dbuser.email, dbuser.username, new_password_raw,))
except:
logging.error('Failed to launch UserHandler._send_recover_account_email: %s' % (dbuser))

def _send_reset_password_email(self, email, username, password):
sent_from = self._root.mail_user
Expand Down
81 changes: 51 additions & 30 deletions protocol/Protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@
#########
# users
'SETACCESS',
'DELETEACCOUNT',
#########
# dev
'STATS',
Expand Down Expand Up @@ -968,6 +969,17 @@ def in_LOGIN(self, client, username, password, cpu='0', local_ip='', sentence_ar
self.out_DENIED(client, username, "Invalid username: '%s'" % username, True)
return

good, reason = self.userdb.check_login_user(username, password)
if not good:
reason += " (%d/%d)" % (1+failed_logins, max_failed_logins)
self.out_DENIED(client, username, reason, True)
return

delay, reason = self._check_delayed_registration(client)
if delay:
self.out_DENIED(client, username, reason, False)
return

banned, reason = self.userdb.check_banned(username, client.ip_address)
if banned:
assert (type(reason) == str)
Expand All @@ -992,33 +1004,25 @@ def in_LOGIN(self, client, username, password, cpu='0', local_ip='', sentence_ar
client.compat.add('b')
else:
client.compat.add(flag)

good, user_or_error = self.userdb.login_user(username, password, client.ip_address, lobby_id, last_id, local_ip, client.country_code)
if (not good):
assert (type(user_or_error) == str)
reason = user_or_error
reason += " (%d/%d)" % (1+failed_logins, max_failed_logins)
self.out_DENIED(client, username, reason, True)
return

assert(user_or_error != None)
assert(type(user_or_error) != str)

# login checks complete
dbuser = self.userdb.login_user(username, password, client.ip_address, lobby_id, last_id, local_ip, client.country_code)

# update local client fields from DB User values
client.access = user_or_error.access
client.access = dbuser.access
self._calc_access(client)
client.set_user_pwrd_salt(user_or_error.username, (user_or_error.password, user_or_error.randsalt))
client.user_id = user_or_error.id
client.lobby_id = user_or_error.lobby_id
client.bot = user_or_error.bot
client.last_id = user_or_error.last_id
client.register_date = user_or_error.register_date
client.last_login = user_or_error.last_login
client.ingame_time = user_or_error.ingame_time
client.email = user_or_error.email
client.set_user_pwrd_salt(dbuser.username, (dbuser.password, dbuser.randsalt))
client.user_id = dbuser.id
client.lobby_id = dbuser.lobby_id
client.bot = dbuser.bot
client.last_id = dbuser.last_id
client.register_date = dbuser.register_date
client.last_login = dbuser.last_login
client.ingame_time = dbuser.ingame_time
client.email = dbuser.email

if (client.access == 'agreement'):
logging.info('[%s] Sent user <%s> the terms of service on session.' % (client.session_id, user_or_error.username))
logging.info('[%s] Sent user <%s> the terms of service on session.' % (client.session_id, dbuser.username))
if self.verificationdb.active():
client.Send("AGREEMENT A verification code has been sent to your email address. Please read our terms of service and then enter your four digit code below.")
client.Send("AGREEMENT ")
Expand All @@ -1027,11 +1031,6 @@ def in_LOGIN(self, client, username, password, cpu='0', local_ip='', sentence_ar
client.Send('AGREEMENTEND')
return

delay, reason = self._check_delayed_registration(client)
if delay:
self.out_DENIED(client, username, reason, False)

# login checks complete
if client.ip_address in self._root.recent_failed_logins:
del self._root.recent_failed_logins[client.ip_address]

Expand Down Expand Up @@ -3123,7 +3122,7 @@ def in_RESETPASSWORD(self, client, email, verification_code):
client.Send("RESETPASSWORDDENIED " + reason)
return

self.verificationdb.reset_password(recover_client.user_id)
self.verificationdb.reset_password(recover_client.user_id, True)
client.Send("RESETPASSWORDACCEPTED %s %s" % (recover_client.email, recover_client.username))
self.out_SERVERMSG(client, "Your password has been reset. Please check your email account." + client.email)
client.Remove("")
Expand Down Expand Up @@ -3152,10 +3151,32 @@ def in_RESETUSERPASSWORD(self, client, username, newmail=None):
self.out_SERVERMSG(client, "The email address '%s' is not valid: %s" % (newmail, reason_new))
return
recover_client.email = newmail
self.userdb.save_user(recover_client)
self.verificationdb.reset_password(recover_client.user_id)
self.userdb.save_user(recover_client)
self.verificationdb.reset_password(recover_client.user_id, False)
self.out_SERVERMSG(client, "An email was sent to '%s' containing a new password for <%s>" % (recover_client.username, recover_client.email))

def in_DELETEACCOUNT(self, client, username):
# schedule the user account for deletion; after a delay during which the account becomes inaccessible
delete_client = self.clientFromUsername(username, True)
if not delete_client:
self.out_SERVERMSG(client, "User <%s> does not exist" % (username))
return

# ensure that account is not logged in while we modify it & deter use of account deletion requests for smurfing
self.in_BANSPECIFIC(client, delete_client.ip_address, 28, "account deletion request scheduled")
if delete_client.email:
self.in_BANSPECIFIC(client, delete_client.email, 28, "account deletion request scheduled")
self.in_KICK(client, username, "account deletion request")

delete_client.ingame_time = 0
delete_client.bot = 0
delete_client.access = "user"
delete_client.email = "" # prevent account recovery
self.userdb.save_user(delete_client)
self.verificationdb.reset_password(delete_client.user_id, False)
# now the account can no longer be accessed & has no ingame time or special status
# -> automated deletion after 28 days

def in_RESENDVERIFICATION(self, client, newmail):
if not self.verificationdb.active():
client.Send("RESENDVERIFICATIONDENIED email verification is currently turned off, you do not need a verification code!")
Expand Down

0 comments on commit 1caf080

Please sign in to comment.