codekingpro/portable-devtools
114k
1import config2from flask import current_app, session, current_app3from flask_login import current_user4from pgadmin.model import db, User, Server5from pgadmin.utils.crypto import encrypt, decrypt6 7 8MASTERPASS_CHECK_TEXT = 'ideas are bulletproof'9 10 11def set_crypt_key(_key, _new_login=True):12 """13 Set the crypt key14 :param _key: The key15 :param _new_login: Is fresh login or password change16 """17 current_app.keyManager.set(_key, _new_login)18 19 20def get_crypt_key():21 """22 Returns the crypt key23 :return: the key24 """25 enc_key = current_app.keyManager.get()26 27 # if desktop mode and master pass disabled then use the password hash28 if not config.MASTER_PASSWORD_REQUIRED \29 and not config.SERVER_MODE:30 return True, current_user.password31 # if desktop mode and master pass enabled32 elif config.MASTER_PASSWORD_REQUIRED and \33 config.MASTER_PASSWORD_HOOK is None\34 and enc_key is None:35 return False, None36 elif not config.MASTER_PASSWORD_REQUIRED and config.SERVER_MODE and \37 'pass_enc_key' in session:38 return True, session['pass_enc_key']39 elif config.MASTER_PASSWORD_REQUIRED and config.SERVER_MODE and \40 config.MASTER_PASSWORD_HOOK and current_user.password is None:41 cmd = config.MASTER_PASSWORD_HOOK42 command = cmd.replace('%u', current_user.username) \43 if '%u' in cmd else cmd44 return get_master_password_from_master_hook(command)45 else:46 return True, enc_key47 48 49def validate_master_password(password):50 """51 Validate the password/key against the stored encrypted text52 :param password: password/key53 :return: Valid or not54 """55 # master pass is incorrect if decryption fails56 try:57 decrypted_text = decrypt(current_user.masterpass_check, password)58 59 if isinstance(decrypted_text, bytes):60 decrypted_text = decrypted_text.decode()61 62 if MASTERPASS_CHECK_TEXT != decrypted_text:63 return False64 else:65 return True66 except Exception:67 False68 69 70def set_masterpass_check_text(password, clear=False):71 """72 Set the encrypted text which will be used later to validate entered key73 :param password: password/key74 :param clear: remove the encrypted text75 """76 try:77 masterpass_check = None78 if not clear:79 masterpass_check = encrypt(MASTERPASS_CHECK_TEXT, password)80 81 # set the encrypted sample text with the new82 # master pass83 db.session.query(User) \84 .filter(User.id == current_user.id) \85 .update({User.masterpass_check: masterpass_check})86 db.session.commit()87 88 except Exception:89 db.session.rollback()90 raise91 92 93def cleanup_master_password():94 """95 Remove the master password and saved passwords from DB which are96 encrypted using master password. Also remove the encrypted text97 """98 99 # also remove the master password check string as it will help if master100 # password entered/enabled again101 set_masterpass_check_text('', clear=True)102 103 from pgadmin.browser.server_groups.servers.utils \104 import remove_saved_passwords105 remove_saved_passwords(current_user.id)106 107 current_app.keyManager.hard_reset()108 109 from pgadmin.utils.driver import get_driver110 driver = get_driver(config.PG_DEFAULT_DRIVER)111 112 for server in Server.query.filter_by(user_id=current_user.id).all():113 manager = driver.connection_manager(server.id)114 manager.update(server)115 116 117def process_masterpass_disabled():118 """119 On master password disable, remove the connection data from session as it120 may have saved password which will cause trouble121 :param session: Flask session122 :param conn_data: connection manager copy from session if any123 """124 if not config.SERVER_MODE and not config.MASTER_PASSWORD_REQUIRED \125 and current_user.masterpass_check is not None:126 cleanup_master_password()127 return True128 129 return False130 131 132def get_master_password_from_master_hook(command):133 """134 This method executes specified command & returns output.135 :param command: Shell command with absolute path136 :return: Output of command.137 """138 import subprocess139 try:140 p = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)141 out, err = p.communicate()142 if p.returncode == 0:143 output = out.decode() if hasattr(out, 'decode') else out144 output = output.strip()145 return True, output146 else:147 error = "Command '{0}' failed, exit-code={1} error = {2}".format(148 command, p.returncode, str(err))149 current_app.logger.error(error)150 return False, None151 except Exception as e:152 current_app.logger.exception(153 'Failed to retrieve master password from the master password hook'154 ' utility.Error: {0}'.format(e)155 )156 return False, None157 