Package entropy :: Package services :: Module auth_interfaces

Source Code for Module entropy.services.auth_interfaces

  1  # -*- coding: utf-8 -*- 
  2  """ 
  3   
  4      @author: Fabio Erculiani <lxnay@sabayonlinux.org> 
  5      @contact: lxnay@sabayonlinux.org 
  6      @copyright: Fabio Erculiani 
  7      @license: GPL-2 
  8   
  9      B{Entropy Services Authentication Interfaces}. 
 10   
 11  """ 
 12   
 13  import os 
 14  import time 
 15  import random 
 16  from entropy.services.skel import Authenticator, RemoteDatabase 
 17  from entropy.exceptions import * 
 18  from entropy.const import etpConst, const_isstring, const_convert_to_unicode 
 19  from entropy.i18n import _ 
 20   
21 -class phpBB3Auth(Authenticator, RemoteDatabase):
22 23 from entropy import tools as entropyTools
24 - def __init__(self):
25 Authenticator.__init__(self) 26 RemoteDatabase.__init__(self) 27 28 self.itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' 29 self.USER_NORMAL = 0 30 self.USER_INACTIVE = 1 31 self.USER_IGNORE = 2 32 self.USER_FOUNDER = 3 33 self.REGISTERED_USERS_GROUP = 7895 34 self.ADMIN_GROUPS = [7893, 7898] 35 self.MODERATOR_GROUPS = [484] 36 self.DEVELOPER_GROUPS = [7900] 37 self.USERNAME_LENGTH_RANGE = list(range(3, 21)) 38 self.PASSWORD_LENGTH_RANGE = list(range(6, 31)) 39 self.PRIVMSGS_NO_BOX = -3 40 self.NOTIFY_EMAIL = 0 41 self.FAKE_USERNAME = 'already_authed' 42 self.USER_AGENT = "Entropy/%s (compatible; %s; %s: %s %s %s)" % ( 43 etpConst['entropyversion'], 44 "Entropy", 45 "UGC", 46 os.uname()[0], 47 os.uname()[4], 48 os.uname()[2], 49 ) 50 self.TABLE_PREFIX = 'phpbb_' 51 self.do_update_session_table = True
52
53 - def validate_username_regex(self, username):
54 allow_name_chars = self._get_config_value("allow_name_chars") 55 if allow_name_chars == "USERNAME_CHARS_ANY": 56 regex = '.+' 57 elif allow_name_chars == "USERNAME_ALPHA_ONLY": 58 regex = '[A-Za-z0-9]+' 59 elif allow_name_chars == "USERNAME_ALPHA_SPACERS": 60 regex = '[A-Za-z0-9-[\]_+ ]+' 61 elif allow_name_chars == "USERNAME_LETTER_NUM": 62 regex = '[a-zA-Z0-9]+' 63 elif allow_name_chars == "USERNAME_LETTER_NUM_SPACERS": 64 regex = '[-\]_+ [a-zA-Z0-9]+' 65 else: # USERNAME_ASCII 66 regex = '[\x01-\x7F]+' 67 regex = "^%s$" % (regex,) 68 import re 69 myreg = re.compile(regex) 70 if myreg.match(username): 71 del myreg 72 return True 73 return False
74
75 - def does_username_exist(self, username, username_clean):
76 self.check_connection() 77 self.cursor.execute('SELECT user_id FROM '+self.TABLE_PREFIX+'users WHERE `username_clean` = %s OR LOWER(`username`) = %s', (username_clean, username.lower(),)) 78 data = self.cursor.fetchone() 79 if not data: return False 80 if not isinstance(data, dict): return False 81 if 'user_id' not in data: return False 82 return True
83
84 - def does_email_exist(self, email):
85 self.check_connection() 86 self.cursor.execute('SELECT user_id FROM '+self.TABLE_PREFIX+'users WHERE `user_email` = %s', (email,)) 87 data = self.cursor.fetchone() 88 if not data: return False 89 if not isinstance(data, dict): return False 90 if 'user_id' not in data: return False 91 return True
92
93 - def is_username_allowed(self, username):
94 self.check_connection() 95 self.cursor.execute('SELECT disallow_id FROM '+self.TABLE_PREFIX+'disallow WHERE `disallow_username` = %s', (username,)) 96 data = self.cursor.fetchone() 97 if not data: return True 98 if not isinstance(data, dict): return True 99 if 'disallow_id' not in data: return True 100 return False
101
102 - def validate_username_string(self, username, username_clean):
103 104 try: 105 const_convert_to_unicode(username.encode('utf-8')) 106 except (UnicodeDecodeError, UnicodeEncodeError,): 107 return False, 'Invalid username' 108 if ("&quot;" in username) or ("'" in username) or ('"' in username) or \ 109 (" " in username): 110 return False, 'Invalid username' 111 112 try: 113 valid = self.validate_username_regex(username) 114 except: 115 return False, 'Username contains bad characters' 116 if not valid: 117 return False, 'Invalid username' 118 119 exists = self.does_username_exist(username, username_clean) 120 if exists: return False, 'Username already taken' 121 122 allowed = self.is_username_allowed(username) 123 if not allowed: return False, 'Username not allowed' 124 125 return True, 'All fine'
126
127 - def _generate_email_hash(self, email):
128 import binascii 129 return str(binascii.crc32(email.lower())) + str(len(email))
130
131 - def activate_user(self, user_id):
132 self.check_connection() 133 self.cursor.execute('UPDATE '+self.TABLE_PREFIX+'users SET user_type = %s WHERE `user_id` = %s', (self.USER_NORMAL, user_id,)) 134 return True, user_id
135
136 - def generate_username_clean(self, username):
137 import re 138 username_clean = username.lower() 139 username_clean = re.sub(r'(?:[\x00-\x1F\x7F]+|(?:\xC2[\x80-\x9F])+)', '', username_clean) 140 username_clean = re.sub(r' {2,}', ' ', username_clean) 141 username_clean = username_clean.strip() 142 return username_clean
143
144 - def register_user(self, username, password, email, activate = False):
145 146 if len(username) not in self.USERNAME_LENGTH_RANGE: 147 return False, 'Username not in range' 148 if len(password) not in self.PASSWORD_LENGTH_RANGE: 149 return False, 'Password not in range' 150 valid = self.entropyTools.is_valid_email(email) 151 if not valid: 152 return False, 'Invalid email' 153 154 # create the clean one 155 username_clean = self.generate_username_clean(username) 156 157 # check username validity 158 status, err_msg = self.validate_username_string(username, username_clean) 159 if not status: return False, err_msg 160 161 # check email 162 exists = self.does_email_exist(email) 163 if exists: return False, 'Email already in use' 164 165 # now cross fingers 166 status, user_id = self.__register(username, username_clean, password, email, activate) 167 if not status: 168 return False, 'Invalid username (duplicated)' 169 170 return True, user_id
171 172
173 - def __register(self, username, username_clean, password, email, activate):
174 175 email_hash = self._generate_email_hash(email) 176 password_hash = self._get_password_hash(password.encode('utf-8')) 177 time_now = int(time.time()) 178 179 user_type = self.USER_INACTIVE 180 if activate: user_type = self.USER_NORMAL 181 182 registration_data = { 183 'username': username, 184 'username_clean': username_clean, 185 'user_password': password_hash, 186 'user_pass_convert': 0, 187 'user_email': email.lower(), 188 'user_email_hash': email_hash, 189 'group_id': self.REGISTERED_USERS_GROUP, 190 'user_type': user_type, 191 'user_permissions': '', 192 'user_timezone': self._get_config_value('board_timezone'), 193 'user_dateformat': self._get_config_value('default_dateformat'), 194 'user_lang': self._get_config_value('default_lang'), 195 'user_style': self._get_config_value('default_style'), 196 'user_actkey': '', 197 'user_ip': '', 198 'user_regdate': time_now, 199 'user_passchg': time_now, 200 'user_options': 895, # ? don't ask me 201 'user_inactive_reason': 0, 202 'user_inactive_time': 0, 203 'user_lastmark': time_now, 204 'user_lastvisit': 0, 205 'user_lastpost_time': 0, 206 'user_lastpage': '', 207 'user_posts': 0, 208 'user_dst': self._get_config_value('board_dst'), 209 'user_colour': '', 210 'user_occ': '', 211 'user_interests': '', 212 'user_avatar': '', 213 'user_avatar_type': 0, 214 'user_avatar_width': 0, 215 'user_avatar_height': 0, 216 'user_new_privmsg': 0, 217 'user_unread_privmsg': 0, 218 'user_last_privmsg': 0, 219 'user_message_rules': 0, 220 'user_full_folder': self.PRIVMSGS_NO_BOX, 221 'user_emailtime': 0, 222 'user_notify': 0, 223 'user_notify_pm': 1, 224 'user_notify_type': self.NOTIFY_EMAIL, 225 'user_allow_pm': 1, 226 'user_allow_viewonline': 1, 227 'user_allow_viewemail': 1, 228 'user_allow_massemail': 1, 229 'user_sig': '', 230 'user_sig_bbcode_uid': '', 231 'user_sig_bbcode_bitfield': '', 232 'user_form_salt': self._get_unique_id(), 233 } 234 235 sql = self._generate_sql('insert', self.TABLE_PREFIX+'users', registration_data) 236 self.cursor.execute(sql) 237 user_id = self.cursor.lastrowid 238 239 # now insert into the default group 240 group_data = { 241 'user_id': user_id, 242 'group_id': self.REGISTERED_USERS_GROUP, 243 'user_pending': 0, 244 } 245 sql = self._generate_sql('insert', self.TABLE_PREFIX+'user_group', group_data) 246 try: 247 self.cursor.execute(sql) 248 except self.mysql_exceptions.IntegrityError as e: 249 # for sure it's about duplicated entry 250 return False, 1062 251 252 # set some misc config shit 253 self._set_config_value('newest_user_id', user_id) 254 self._set_config_value('newest_username', username) 255 self._set_config_value('num_users', int(self._get_config_value('num_users'))+1) 256 self.cursor.execute('SELECT group_colour FROM '+self.TABLE_PREFIX+'groups WHERE group_id = %s', (group_data['group_id'],)) 257 data = self.cursor.fetchone() 258 gcolor = None 259 if isinstance(data, dict): 260 if 'group_colour' in data: 261 gcolor = data['group_colour'] 262 if gcolor: self._set_config_value('newest_user_colour', gcolor) 263 264 return True, user_id
265 266
267 - def login(self):
268 self.check_connection() 269 self.check_login_data() 270 271 if 'username' not in self.login_data: 272 raise PermissionDenied('PermissionDenied: %s' % (_('no username specified'),)) 273 elif 'password' not in self.login_data: 274 raise PermissionDenied('PermissionDenied: %s' % (_('no password specified'),)) 275 276 if not self.login_data['password']: 277 raise PermissionDenied('PermissionDenied: %s' % (_('empty password'),)) 278 elif not self.login_data['username']: 279 raise PermissionDenied('PermissionDenied: %s' % (_('empty username'),)) 280 281 self.cursor.execute('SELECT * FROM '+self.TABLE_PREFIX+'users WHERE username = %s', (self.login_data['username'],)) 282 data = self.cursor.fetchone() 283 if not data: 284 raise PermissionDenied('PermissionDenied: %s' % (_('user not found'),)) 285 286 if data['user_pass_convert']: 287 raise PermissionDenied('PermissionDenied: %s' % ( 288 _('you need to login on the website to update your password format'), 289 ) 290 ) 291 292 valid = self._phpbb3_check_hash(self.login_data['password'], data['user_password']) 293 if not valid: 294 raise PermissionDenied('PermissionDenied: %s' % (_('wrong password'),)) 295 296 user_type = data['user_type'] 297 if (user_type == self.USER_INACTIVE) or (user_type == self.USER_IGNORE): 298 raise PermissionDenied('PermissionDenied: %s' % (_('user inactive'),)) 299 300 banned = self.is_user_banned(data['user_id']) 301 if banned: 302 raise PermissionDenied('PermissionDenied: %s' % (_('user banned'),)) 303 304 self.login_data.update(data) 305 self.logged_in = True 306 return self.logged_in
307
308 - def disconnect(self):
309 if self.is_logged_in(): 310 self.logout() 311 RemoteDatabase.disconnect(self)
312
313 - def logout(self):
314 self.check_connection() 315 self.check_login_data() 316 self.logged_in = False 317 self.login_data.clear() 318 return True
319
320 - def get_user_data(self):
321 self.check_connection() 322 self.check_login_data() 323 self.check_logged_in() 324 325 self.cursor.execute('SELECT * FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],)) 326 return self.cursor.fetchone()
327
328 - def get_user_birthday(self):
329 self.check_connection() 330 self.check_login_data() 331 self.check_logged_in() 332 333 self.cursor.execute('SELECT user_birthday FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],)) 334 bday = self.cursor.fetchone() 335 if not bday: 336 return None 337 elif 'user_birthday' not in bday: 338 return None 339 return bday['user_birthday']
340
341 - def get_username(self):
342 self.check_connection() 343 self.check_login_data() 344 self.check_logged_in() 345 346 self.cursor.execute('SELECT username_clean FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],)) 347 data = self.cursor.fetchone() 348 if not data: 349 return '' 350 elif 'username_clean' not in data: 351 return '' 352 return data['username_clean']
353
354 - def is_developer(self):
355 self.check_connection() 356 self.check_login_data() 357 self.check_logged_in() 358 359 # search into phpbb_groups 360 groups = self.get_user_groups() 361 for group in groups: 362 if group in self.DEVELOPER_GROUPS: 363 return True 364 365 return False
366
367 - def is_administrator(self):
368 self.check_connection() 369 self.check_login_data() 370 self.check_logged_in() 371 372 self.cursor.execute('SELECT user_type FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],)) 373 data = self.cursor.fetchone() 374 if data: 375 if data['user_type'] == self.USER_FOUNDER: 376 return True 377 378 # search into phpbb_groups 379 groups = self.get_user_groups() 380 for group in groups: 381 if group in self.ADMIN_GROUPS: 382 return True 383 384 return False
385
386 - def is_moderator(self):
387 self.check_connection() 388 self.check_login_data() 389 self.check_logged_in() 390 391 # search into phpbb_groups 392 groups = self.get_user_groups() 393 for group in groups: 394 if group in self.MODERATOR_GROUPS: 395 return True 396 397 return False
398
399 - def is_user(self):
400 self.check_connection() 401 self.check_login_data() 402 self.check_logged_in() 403 404 if self.is_moderator(): 405 return False 406 elif self.is_administrator(): 407 return False 408 elif self.is_developer(): 409 return False 410 411 self.cursor.execute('SELECT user_type,user_id FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],)) 412 data = self.cursor.fetchone() 413 if not data: 414 return False 415 if self.is_user_banned(data['user_id']): 416 return False 417 elif data['user_type'] in [self.USER_NORMAL]: 418 return True 419 420 return False
421 422 # user == user_id
423 - def is_user_banned(self, user):
424 self.check_connection() 425 self.cursor.execute('SELECT ban_userid FROM '+self.TABLE_PREFIX+'banlist WHERE ban_userid = %s', (user,)) 426 data = self.cursor.fetchone() 427 if data: 428 return True 429 return False
430
431 - def is_in_group(self, group):
432 self.check_connection() 433 self.check_login_data() 434 self.check_logged_in() 435 groups = self.get_user_groups() 436 if isinstance(group, int): 437 if group in groups: 438 return True 439 elif const_isstring(group): 440 self.cursor.execute('SELECT group_id FROM '+self.TABLE_PREFIX+'groups WHERE group_name = %s', (group,)) 441 data = self.cursor.fetchone() 442 if not data: 443 return False 444 elif data['group_id'] in groups: 445 return True 446 447 return False
448
449 - def get_user_groups(self):
450 self.check_connection() 451 self.check_login_data() 452 self.check_logged_in() 453 454 self.cursor.execute('SELECT '+self.TABLE_PREFIX+'user_group.group_id,'+self.TABLE_PREFIX+'groups.group_name FROM '+self.TABLE_PREFIX+'user_group,'+self.TABLE_PREFIX+'users,'+self.TABLE_PREFIX+'groups WHERE '+self.TABLE_PREFIX+'users.user_id = %s and '+self.TABLE_PREFIX+'users.user_id = '+self.TABLE_PREFIX+'user_group.user_id and '+self.TABLE_PREFIX+'user_group.group_id = '+self.TABLE_PREFIX+'groups.group_id', (self.login_data['user_id'],)) 455 data = self.cursor.fetchall() 456 mydata = {} 457 for mydict in data: 458 mydata[mydict['group_id']] = mydict['group_name'] 459 460 return mydata
461
462 - def get_user_group(self):
463 self.check_connection() 464 self.check_login_data() 465 self.check_logged_in() 466 467 self.cursor.execute('SELECT group_id FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],)) 468 data = self.cursor.fetchone() 469 if data: 470 if 'group_id' in data: 471 return data['group_id'] 472 473 return -1
474
475 - def get_user_id(self):
476 self.check_connection() 477 self.check_login_data() 478 self.check_logged_in() 479 return self.login_data['user_id']
480
481 - def get_permission_data(self):
482 self.check_connection() 483 self.check_login_data() 484 self.check_logged_in() 485 self.cursor.execute('SELECT user_permissions FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],)) 486 return self.cursor.fetchone()
487
488 - def update_email(self, email):
489 self.check_connection() 490 self.check_login_data() 491 self.check_logged_in() 492 493 email_hash = self._generate_email_hash(email) 494 mydata = { 495 'user_email_hash': email_hash, 496 'user_email': email.lower(), 497 } 498 499 try: 500 sql = self._generate_sql("update", self.TABLE_PREFIX+'users', mydata, 'user_id = %s' % (self.login_data['user_id'],)) 501 self.cursor.execute(sql) 502 return True 503 except Exception: 504 return False
505
506 - def update_password_hash(self, password_hash):
507 self.check_connection() 508 self.check_login_data() 509 self.check_logged_in() 510 511 mydata = { 512 'user_password': password_hash, 513 } 514 515 try: 516 sql = self._generate_sql("update", self.TABLE_PREFIX+'users', mydata, 'user_id = %s' % (self.login_data['user_id'],)) 517 self.cursor.execute(sql) 518 return True 519 except Exception: 520 return False
521
522 - def get_email(self):
523 self.check_connection() 524 self.check_login_data() 525 self.check_logged_in() 526 self.cursor.execute('SELECT user_email FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (self.login_data['user_id'],)) 527 data = self.cursor.fetchone() 528 if not data: 529 return '' 530 elif 'user_email' not in data: 531 return '' 532 return data['user_email']
533
534 - def update_user_id_profile(self, profile_data):
535 self.check_connection() 536 self.check_login_data() 537 self.check_logged_in() 538 539 # filter valid params 540 valid_params = [ 541 "user_icq", "user_yim", "user_msnm", 542 "user_jabber", "user_website", "user_from", 543 "user_interests", "user_occ", "user_birthday", 544 "user_sig" 545 ] 546 547 my_params = {} 548 for param in valid_params: 549 d = profile_data.get(param) 550 if d == None: continue 551 my_params[param] = d 552 553 if not my_params: 554 return False, 'no parameters' 555 556 557 # validate parameters 558 b_day = my_params.get('user_birthday') 559 if const_isstring(b_day): 560 import re 561 myre = re.compile("(0[1-9]|[12][0-9]|3[01])[-](0[1-9]|1[012])[-](19|20)\d\d") 562 if not myre.match(b_day): 563 del my_params['user_birthday'] 564 565 try: 566 sql = self._generate_sql("update", self.TABLE_PREFIX+'users', my_params, 'user_id = %s' % (self.login_data['user_id'],)) 567 self.cursor.execute(sql) 568 return True, None 569 except Exception as e: 570 return False, str(e)
571 572
573 - def _set_config_value(self, config_name, data):
574 self.cursor.execute('UPDATE '+self.TABLE_PREFIX+'config SET config_value = %s WHERE config_name = %s', (data, config_name,))
575
576 - def _get_config_value(self, config_name):
577 self.check_connection() 578 self.cursor.execute('SELECT config_value FROM '+self.TABLE_PREFIX+'config WHERE config_name = %s', (config_name,)) 579 myconfig = self.cursor.fetchone() 580 if isinstance(myconfig, dict): 581 if 'config_value' in myconfig: 582 return myconfig['config_value'] 583 return None
584
585 - def _update_session_table(self, user_id, ip_address):
586 self.check_connection() 587 time_now = int(time.time()) 588 autologin = self._get_config_value("allow_autologin") 589 self.cursor.execute('SELECT user_allow_viewonline FROM '+self.TABLE_PREFIX+'users WHERE user_id = %s', (user_id,)) 590 myuserprefs = self.cursor.fetchone() 591 session_admin = 0 592 session_data = { 593 'session_id': None, 594 'session_user_id': user_id, 595 'session_last_visit': time_now, 596 'session_start': time_now, 597 'session_time': time_now, 598 'session_ip': ip_address, 599 'session_browser': self.USER_AGENT, 600 'session_forwarded_for': '', 601 'session_page': 'index.php', 602 'session_viewonline': myuserprefs['user_allow_viewonline'], 603 'session_autologin': autologin, 604 'session_admin': session_admin, 605 'session_forum_id': 0, 606 } 607 import hashlib 608 m = hashlib.md5() 609 m.update(str(user_id)+str(time_now)+str(self.USER_AGENT)+str(ip_address)+str(autologin)+str(myuserprefs['user_allow_viewonline'])) 610 session_data['session_id'] = m.hexdigest() 611 612 self.cursor.execute('SELECT * FROM '+self.TABLE_PREFIX+'sessions WHERE session_user_id = %s', (user_id,)) 613 mydata = self.cursor.fetchone() 614 do_update = False 615 if mydata: 616 do_update = True 617 # update 618 session_data['session_id'] = mydata['session_id'] 619 session_data['session_viewonline'] = mydata['session_viewonline'] 620 session_data['session_autologin'] = mydata['session_autologin'] 621 session_data['session_forwarded_for'] = mydata['session_forwarded_for'] 622 session_data['session_forum_id'] = mydata['session_forum_id'] 623 session_data['session_page'] = mydata['session_page'] 624 session_data['session_browser'] = mydata['session_browser'] 625 session_data['session_admin'] = mydata['session_admin'] 626 627 if do_update: 628 where = "session_id = '%s'" % (session_data['session_id'],) 629 del session_data['session_id'] 630 sql = self._generate_sql('update', self.TABLE_PREFIX+'sessions', session_data, where) 631 else: 632 sql = self._generate_sql('insert', self.TABLE_PREFIX+'sessions', session_data) 633 if sql: 634 self.cursor.execute(sql) 635 self.dbconn.commit()
636 637
638 - def _is_ip_banned(self, ip):
639 self.check_connection() 640 self.cursor.execute('SELECT ban_ip FROM '+self.TABLE_PREFIX+'banlist WHERE ban_ip = %s', (ip,)) 641 data = self.cursor.fetchone() 642 if data: 643 return True 644 return False
645
646 - def _get_unique_id(self):
647 import hashlib 648 m = hashlib.md5() 649 rnd = str(abs(hash(os.urandom(1)))) 650 m.update(rnd) 651 x = m.hexdigest()[:-16] 652 del m 653 return x
654
655 - def _get_random_number(self):
656 myrand = 0 657 low_n = 100000 658 high_n = 999999 659 while (myrand < low_n) or (myrand > high_n): 660 try: 661 myrand = hash(os.urandom(1))%high_n 662 except NotImplementedError: 663 random.seed() 664 myrand = random.randint(low_n, high_n) 665 return myrand
666
667 - def _get_password_hash(self, password):
668 669 #random_state = self._get_unique_id() 670 myrandom = str(self._get_random_number()) 671 672 myhash = self._hash_crypt_private(password, self._hash_gensalt_private(myrandom)) 673 674 if len(myhash) == 34: 675 return myhash 676 677 import hashlib 678 m = hashlib.md5() 679 m.update(myhash) 680 return m.hexdigest()
681 682
683 - def _hash_gensalt_private(self, myinput, iteration_count_log2 = 6):
684 685 if (iteration_count_log2 < 4) or (iteration_count_log2 > 31): 686 iteration_count_log2 = 8 687 688 myoutput = '$H$' 689 myoutput += self.itoa64[min(iteration_count_log2 + 5, 30)] 690 myoutput += self._hash_encode64(myinput, 6) 691 692 return myoutput
693
694 - def _hash_crypt_private(self, password, setting):
695 696 myoutput = '*' 697 # Check for correct hash 698 if setting[:3] != '$H$': 699 return myoutput 700 701 count_log2 = self.itoa64.find(setting[3]) 702 if count_log2 == -1: count_log2 = 0 703 704 if (count_log2 < 7) or (count_log2 > 30): 705 return myoutput 706 707 count = 1 << count_log2 708 salt = setting[4:12] 709 710 if len(salt) != 8: 711 return myoutput 712 713 import hashlib 714 m = hashlib.md5() 715 m.update(salt+password) 716 myhash = m.digest() 717 while count: 718 m = hashlib.md5() 719 m.update(myhash+password) 720 myhash = m.digest() 721 count -= 1 722 723 myoutput = setting[:12] 724 myoutput += self._hash_encode64(myhash, 16) 725 726 return myoutput
727
728 - def _hash_encode64(self, myinput, count):
729 730 output = '' 731 i = 0 732 while i < count: 733 734 value = ord(myinput[i]) 735 i += 1 736 output += self.itoa64[value & 0x3f] 737 if i < count: 738 value |= ord(myinput[i]) << 8 739 740 output += self.itoa64[(value >> 6) & 0x3f] 741 742 if i >= count: 743 break 744 i += 1 745 746 if i < count: 747 value |= ord(myinput[i]) << 16 748 749 output += self.itoa64[(value >> 12) & 0x3f] 750 751 if (i >= count): 752 break 753 i += 1 754 755 output += self.itoa64[(value >> 18) & 0x3f] 756 757 return output
758
759 - def _phpbb3_check_hash(self, password, myhash):
760 761 if len(myhash) == 34: 762 return self._hash_crypt_private(password, myhash) == myhash 763 764 import hashlib 765 m = hashlib.md5() 766 m.update(password) 767 rhash = m.hexdigest() 768 return rhash == myhash
769