def _create_new_key(self, vcard, keytype): passphrase = okay_random(26, self.session.config.master_key ).lower() random_uid = vcard.random_uid bits = int(keytype.replace('RSA', '')) key_args = { # FIXME: EC keys! 'bits': bits, 'name': vcard.fn, 'email': vcard.email, 'passphrase': passphrase, 'comment': '' } event = Event(source=self, message=_('Generating new %d bit PGP key. ' 'This may take some time!') % bits, flags=Event.INCOMPLETE, data={'keygen_started': int(time.time()), 'profile_id': random_uid}, private_data=key_args) self._key_generator = GnuPGKeyGenerator( # FIXME: Passphrase handling is a problem here variables=dict_merge(GnuPGKeyGenerator.VARIABLES, key_args), on_complete=(random_uid, lambda: self._new_key_created(event, random_uid, passphrase)) ) self._key_generator.start() self.session.config.event_log.log_event(event)
def setup_command(self, session): changed = authed = False results = { 'secret_keys': self.list_secret_keys(), } error_info = None if self.data.get('_method') == 'POST' or self._testing(): # 1st, are we choosing or creating a new key? choose_key = self.data.get('choose_key', [''])[0] if choose_key and not error_info: if (choose_key not in results['secret_keys'] and choose_key != '!CREATE'): error_info = (_('Invalid key'), { 'invalid_key': True, 'chosen_key': choose_key }) # 2nd, check authentication... # # FIXME: Creating a new key will allow a malicious actor to # bypass authentication and change settings. # try: passphrase = self.data.get('passphrase', [''])[0] passphrase2 = self.data.get('passphrase_confirm', [''])[0] chosen_key = ((not error_info) and choose_key ) or session.config.prefs.gpg_recipient if not error_info: assert(passphrase == passphrase2) if chosen_key == '!CREATE': assert(passphrase != '') sps = SecurePassphraseStorage(passphrase) elif chosen_key: sps = mailpile.auth.VerifyAndStorePassphrase( session.config, passphrase=passphrase, key=chosen_key) else: sps = mailpile.auth.VerifyAndStorePassphrase( session.config, passphrase=passphrase) if not chosen_key: choose_key = '!CREATE' results['updated_passphrase'] = True session.config.gnupg_passphrase.data = sps.data mailpile.auth.SetLoggedIn(self) except AssertionError: error_info = (_('Invalid passphrase'), { 'invalid_passphrase': True, 'chosen_key': session.config.prefs.gpg_recipient }) # 3rd, if necessary master key and/or GPG key with BLOCK_HTTPD_LOCK, Idle_HTTPD(): if choose_key and not error_info: session.config.prefs.gpg_recipient = choose_key # FIXME: This should probably only happen if the GPG # key was successfully created. self.make_master_key() changed = True with Setup.KEY_WORKER_LOCK: if ((not error_info) and (session.config.prefs.gpg_recipient == '!CREATE') and (Setup.KEY_CREATING_THREAD is None or Setup.KEY_CREATING_THREAD.failed)): gk = GnuPGKeyGenerator( sps=session.config.gnupg_passphrase, on_complete=('notify', lambda: self.gpg_key_ready(gk))) Setup.KEY_CREATING_THREAD = gk Setup.KEY_CREATING_THREAD.start() # Finally we update misc. settings for key in self.HTTP_POST_VARS.keys(): # FIXME: This should probably only happen if the GPG # key was successfully created. # Continue iff all is well... if error_info: break if key in (['choose_key', 'passphrase', 'passphrase_confirm'] + TestableWebbable.HTTP_POST_VARS.keys()): continue try: val = self.data.get(key, [''])[0] if val: session.config.prefs[key] = self.TRUTHY[val.lower()] changed = True except (ValueError, KeyError): error_info = (_('Invalid preference'), { 'invalid_setting': True, 'variable': key }) results.update({ 'creating_key': (Setup.KEY_CREATING_THREAD is not None and Setup.KEY_CREATING_THREAD.running), 'creating_failed': (Setup.KEY_CREATING_THREAD is not None and Setup.KEY_CREATING_THREAD.failed), 'chosen_key': session.config.prefs.gpg_recipient, 'prefs': { 'index_encrypted': session.config.prefs.index_encrypted, 'obfuscate_index': session.config.prefs.obfuscate_index, 'encrypt_mail': session.config.prefs.encrypt_mail, 'encrypt_index': session.config.prefs.encrypt_index, 'encrypt_vcards': session.config.prefs.encrypt_vcards, 'encrypt_events': session.config.prefs.encrypt_events, 'encrypt_misc': session.config.prefs.encrypt_misc } }) if changed: self._background_save(config=True) if error_info: return self._error(error_info[0], info=error_info[1], result=results) elif changed: return self._success(_('Updated crypto preferences'), results) else: return self._success(_('Configure crypto preferences'), results)