import psycopg2 from Crypto.Hash import SHA512 from tojauth import TOJAuth from asyncdb import AsyncDB import imc.proxy import config class User: auth_accessid = 2 USERNAME_LEN_MIN = 5 USERNAME_LEN_MAX = 50 PASSWORD_LEN_MIN = 5 PASSWORD_LEN_MAX = 50 NICKNAME_LEN_MIN = 1 NICKNAME_LEN_MAX = 50 EMAIL_LEN_MIN = 5 EMAIL_LEN_MAX = 100 AVATAR_LEN_MIN = 0 AVATAR_LEN_MAX = 200 ABOUTME_LEN_MIN = 0 ABOUTME_LEN_MAX = 1000 def __init__(self, mod_iden): User.instance = self User.db = AsyncDB(config.CORE_DBNAME, config.CORE_DBUSER, config.CORE_DBPASSWORD) User.mod_iden = mod_iden @imc.async.caller def register(self, username, password, nickname, email, avatar, aboutme): if( type(username) != str or type(password) != str or type(nickname) != str or type(email) != str or type(avatar) != str or type(aboutme) != str ): return 'Eparameter' if len(username) < self.USERNAME_LEN_MIN: return 'Eusername_too_short' elif len(username) > self.USERNAME_LEN_MAX: return 'Eusername_too_long' elif len(password) < self.PASSWORD_LEN_MIN: return 'Epassword_too_short' elif len(password) > self.PASSWORD_LEN_MAX: return 'Epassword_too_long' elif len(nickname) < self.NICKNAME_LEN_MIN: return 'Enickname_too_short' elif len(nickname) > self.NICKNAME_LEN_MAX: return 'Enickname_too_long' elif len(email) < self.EMAIL_LEN_MIN: return 'Eemail_too_short' elif len(email) > self.EMAIL_LEN_MAX: return 'Eemail_too_long' elif len(avatar) < self.AVATAR_LEN_MIN: return 'Eavatar_too_short' elif len(avatar) > self.AVATAR_LEN_MAX: return 'Eavatar_too_long' elif len(aboutme) < self.ABOUTME_LEN_MIN: return 'Eaboutme_too_short' elif len(aboutme) > self.ABOUTME_LEN_MAX: return 'Eaboutme_too_long' passhash = self._password_hash(password) with TOJAuth.change_current_iden(self.mod_iden): try: uid = self._create_user( username, passhash, nickname, email, avatar, aboutme) except psycopg2.IntegrityError: return 'Eusername_already_exists' return {'uid' : uid} @TOJAuth.check_access(auth_accessid, TOJAuth.ACCESS_EXECUTE) def _create_user(self, username, passhash, nickname, email, avatar, aboutme): roleid = TOJAuth.instance.create_role(username, TOJAuth.ROLETYPE_USER) cur = self.db.cursor() sqlstr = ('INSERT INTO "USER" ("username", "passhash", "nickname", ' '"email", "avatar", "aboutme", "idenid") ' 'VALUES (%s, %s, %s, %s, %s, %s, %s) RETURNING "uid";') sqlarr = (username, passhash, nickname, email, avatar, aboutme, roleid) cur.execute(sqlstr, sqlarr) for data in cur: uid = data[0] return uid @imc.async.caller def login(self, username, password): if( type(username) != str or type(password) != str ): return 'Eparameter' uid = self.get_uid_by_username(username) if uid == None: return 'Eno_such_uid' passhash = self._password_hash(password) cur = self.db.cursor() sqlstr = ('SELECT "idenid" FROM "USER" WHERE "uid" = %s ' 'AND "passhash" = %s;') sqlarr = (uid, passhash) cur.execute(sqlstr, sqlarr) idenid = None for data in cur: idenid = data[0] if idenid == None: return 'Ewrong_password' linkclass = TOJAuth.get_current_iden()['linkclass'] linkid = TOJAuth.get_current_iden()['linkid'] with TOJAuth.change_current_iden(self.mod_iden): idendesc = TOJAuth.instance.create_iden( linkclass, linkid, idenid, TOJAuth.ROLETYPE_USER, {'uid' : uid} ) ret = { 'idendesc' : idendesc, 'uid' : uid, 'hash' : self._uid_passhash_hash(uid, passhash) } return ret @imc.async.caller def cookie_login(self, uid, uphash): if( type(uid) != int or type(uphash) != str ): return 'Eparameter' idenid = None real_uphash = None cur = self.db.cursor() sqlstr = ('SELECT "idenid", "passhash" FROM "USER" WHERE "uid" = %s;') sqlarr = (uid, ) cur.execute(sqlstr, sqlarr) for data in cur: idenid = data[0] real_uphash = self._uid_passhash_hash(uid, data[1]) if idenid == None: return 'Eno_such_uid' if real_uphash != uphash: return 'Ewrong_uphash' linkclass = TOJAuth.get_current_iden()['linkclass'] linkid = TOJAuth.get_current_iden()['linkid'] with TOJAuth.change_current_iden(self.mod_iden): idendesc = TOJAuth.instance.create_iden( linkclass, linkid, idenid, TOJAuth.ROLETYPE_USER, {'uid' : uid} ) ret = { 'idendesc' : idendesc, 'uid' : uid, 'hash' : uphash } return ret @imc.async.caller def get_user_info(self, uid): if( type(uid) != int ): return 'Eparameter' ret = self._get_user_info_by_uid(uid) if ret == None: return 'Eno_such_uid' return ret @imc.async.caller def set_user_info(self, uid, nickname, email, avatar, aboutme): if( type(uid) != int or type(nickname) != str or type(email) != str or type(avatar) != str or type(aboutme) != str ): return 'Eparameter' if len(nickname) < self.NICKNAME_LEN_MIN: return 'Enickname_too_short' elif len(nickname) > self.NICKNAME_LEN_MAX: return 'Enickname_too_long' elif len(email) < self.EMAIL_LEN_MIN: return 'Eemail_too_short' elif len(email) > self.EMAIL_LEN_MAX: return 'Eemail_too_long' elif len(avatar) < self.AVATAR_LEN_MIN: return 'Eavatar_too_short' elif len(avatar) > self.AVATAR_LEN_MAX: return 'Eavatar_too_long' elif len(aboutme) < self.ABOUTME_LEN_MIN: return 'Eaboutme_too_short' elif len(aboutme) > self.ABOUTME_LEN_MAX: return 'Eaboutme_too_long' idenid = self.get_idenid_by_uid(uid) if idenid == None: return 'Eno_such_uid' if idenid != TOJAuth.get_current_iden()['idenid']: TOJAuth.check_access( self.auth_accessid, TOJAuth.ACCESS_EXECUTE)(lambda x:x)(0) cur = self.db.cursor() sqlstr = ('UPDATE "USER" SET "nickname" = %s, "email" = %s, ' '"avatar" = %s, "aboutme" = %s WHERE "uid" = %s;') sqlarr = (nickname, email, avatar, aboutme, uid) cur.execute(sqlstr, sqlarr) @imc.async.caller def change_user_password(self, uid, old_password, new_password): if( type(uid) != int or type(old_password) != str or type(new_password) != str ): return 'Eparameter' if len(new_password) < self.PASSWORD_LEN_MIN: return 'Epassword_too_short' elif len(new_password) > self.PASSWORD_LEN_MAX: return 'Epassword_too_long' idenid = self.get_idenid_by_uid(uid) if idenid == None: return 'Eno_such_uid' if idenid != TOJAuth.get_current_iden()['idenid']: TOJAuth.check_access( self.auth_accessid, TOJAuth.ACCESS_EXECUTE)(lambda x:x)(0) old_passhash = self._password_hash(old_password) cur = self.db.cursor() sqlstr = ('SELECT "idenid" FROM "USER" WHERE "uid" = %s ' 'AND "passhash" = %s;') sqlarr = (uid, old_passhash) cur.execute(sqlstr, sqlarr) idenid = None for data in cur: idenid = data[0] if idenid == None: return 'Ewrong_old_password' new_passhash = self._password_hash(new_password) sqlstr = ('UPDATE "USER" SET "passhash" = %s WHERE "uid" = %s;') sqlarr = (new_passhash, uid) cur.execute(sqlstr, sqlarr) @imc.async.caller def oauth_login(self): raise NotImplementedError def _password_hash(self, password): h = SHA512.new(bytes(password + config.USER_PASSHASH_SALT, 'utf-8')) return h.hexdigest() def _uid_passhash_hash(self, uid, passhash): return self._password_hash( 'GENGJIAN_WEISUO_KING^^' + str(uid) + '@E__E@' + passhash + 'Yo!') def _get_user_info_by_uid(self, uid): cur = self.db.cursor() sqlstr = ('SELECT * FROM "USER" WHERE "uid" = %s;') sqlarr = (uid, ) cur.execute(sqlstr, sqlarr) ret = None for data in cur: ret = {} ret['uid'] = data[0] ret['username'] = data[1] ret['nickname'] = data[3] ret['email'] = data[4] ret['avatar'] = data[5] ret['aboutme'] = data[6] return ret def get_idenid_by_uid(self, uid): cur = self.db.cursor() sqlstr = ('SELECT "idenid" FROM "USER" WHERE "uid" = %s;') sqlarr = (uid, ) cur.execute(sqlstr, sqlarr) ret = None for data in cur: ret = data[0] return ret def get_uid_by_username(self, username): cur = self.db.cursor() sqlstr = ('SELECT "uid" FROM "USER" WHERE "username" = %s;') sqlarr = (username, ) cur.execute(sqlstr, sqlarr) uid = None for data in cur: uid = data[0] return uid def does_username_exist(self, username): uid = self.get_uid_by_username(username) return uid != None