import psycopg2 from Crypto.Hash import SHA512 from tojauth import TOJAuth from asyncdb import AsyncDB import imc.async from imc.proxy import Proxy import config import mod class UserMg: _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 COVER_LEN_MIN = 0 COVER_LEN_MAX = 200 def __init__(self, mod_idendesc, get_link_fn): UserMg.db = AsyncDB(config.CORE_DBNAME, config.CORE_DBUSER, config.CORE_DBPASSWORD) UserMg._idendesc = mod_idendesc self.get_link = get_link_fn Proxy.instance.register_call( 'core/user/', 'register', self.register) Proxy.instance.register_call( 'core/user/', 'login', self.login) Proxy.instance.register_call( 'core/user/', 'cookie_login', self.cookie_login) Proxy.instance.register_call( 'core/user/', 'get_user_info', self.get_user_info) Proxy.instance.register_call( 'core/user/', 'set_user_info', self.set_user_info) Proxy.instance.register_call( 'core/user/', 'change_user_password', self.change_user_password) Proxy.instance.register_call( 'core/user/', 'list_auth', self.list_auth) def unload(self): Proxy.instance.unregister_call( 'core/user/', 'register') Proxy.instance.unregister_call( 'core/user/', 'login') Proxy.instance.unregister_call( 'core/user/', 'cookie_login') Proxy.instance.unregister_call( 'core/user/', 'get_user_info') Proxy.instance.unregister_call( 'core/user/', 'set_user_info') Proxy.instance.unregister_call( 'core/user/', 'change_user_password') Proxy.instance.unregister_call( 'core/user/', 'list_auth') @imc.async.caller def register( self, username, password, nickname, email, avatar, aboutme, cover ): if( type(username) != str or type(password) != str or type(nickname) != str or type(email) != str or type(avatar) != str or type(aboutme) != str or type(cover) != 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' elif len(cover) < self.COVER_LEN_MIN: return 'Ecover_too_short' elif len(cover) > self.COVER_LEN_MAX: return 'Ecover_too_long' passhash = self._password_hash(password) with TOJAuth.change_current_iden(self._idendesc): try: uid = self._create_user( username, passhash, nickname, email, avatar, aboutme, cover ) except psycopg2.IntegrityError: return 'Eusername_exists' return {'uid' : uid} @TOJAuth.check_access(_accessid, TOJAuth.ACCESS_EXECUTE) def _create_user( self, username, passhash, nickname, email, avatar, aboutme, cover ): roleid = TOJAuth.instance.create_role(username, TOJAuth.ROLETYPE_USER) with TOJAuth.change_current_iden(self._idendesc): TOJAuth.instance.set_role_relation( roleid, TOJAuth.ROLEID_USER_GROUP) cur = self.db.cursor() sqlstr = ('INSERT INTO "USER" ("username", "passhash", "nickname", ' '"email", "avatar", "aboutme", "cover", "idenid") ' 'VALUES (%s, %s, %s, %s, %s, %s, %s, %s) RETURNING "uid";') sqlarr = ( username, passhash, nickname, email, avatar, aboutme, cover, roleid ) cur.execute(sqlstr, sqlarr) for data in cur: uid = data[0] with TOJAuth.change_current_iden(self._idendesc): mod.Notice.create_unseen_count(uid) 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 'Elogin_failed' 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 'Elogin_failed' client_link = TOJAuth.get_current_iden()['link'] with TOJAuth.change_current_iden(self._idendesc): stat,data = Proxy.instance.call(self.get_link('center') + 'core/', 'create_iden', 10000, client_link, idenid, TOJAuth.ROLETYPE_USER, {'uid' : uid}) if stat == False: return 'Einternal' ret = { 'idendesc' : data, '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 'Elogin_failed' if real_uphash != uphash: return 'Elogin_failed' client_link = TOJAuth.get_current_iden()['link'] with TOJAuth.change_current_iden(self._idendesc): stat,data = Proxy.instance.call(self.get_link('center') + 'core/', 'create_iden', 10000, client_link, idenid, TOJAuth.ROLETYPE_USER, {'uid' : uid}) if stat == False: return 'Einternal' ret = { 'idendesc' : data, '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, cover): if( type(uid) != int or type(nickname) != str or type(email) != str or type(avatar) != str or type(aboutme) != str or type(cover) != 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' elif len(cover) < self.COVER_LEN_MIN: return 'Ecover_too_short' elif len(cover) > self.COVER_LEN_MAX: return 'Ecover_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._accessid, TOJAuth.ACCESS_EXECUTE)(lambda x:x)(0) cur = self.db.cursor() sqlstr = ('UPDATE "USER" SET "nickname" = %s, "email" = %s, ' '"avatar" = %s, "aboutme" = %s, "cover" = %s WHERE ' '"uid" = %s;') sqlarr = (nickname, email, avatar, aboutme, cover, uid) cur.execute(sqlstr, sqlarr) return 'Success' @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._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) return 'Success' @imc.async.caller def oauth_login(self): raise NotImplementedError @imc.async.caller def list_auth(self): uid = self.get_current_uid() if uid == None: return 'Euid' idenid = self.get_idenid_by_uid(uid) with TOJAuth.change_current_iden(self._idendesc): auth_list = TOJAuth.instance.get_user_auth_list(idenid) return auth_list 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 "uid", "username", "nickname", "email", "avatar", ' '"aboutme", "cover" 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[2] ret['email'] = data[3] ret['avatar'] = data[4] ret['aboutme'] = data[5] ret['cover'] = data[6] uid = self.get_current_uid() if uid != ret['uid']: try: TOJAuth.check_access_func( self._accessid, TOJAuth.ACCESS_EXECUTE) except Exception: del ret['email'] 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 def does_uid_exist(self, uid): idenid = self.get_idenid_by_uid(uid) return idenid != None @staticmethod def get_current_uid(): user_iden = TOJAuth.get_current_iden() try: uid = user_iden['uid'] except KeyError: return None return uid