package org.mercury_im.messenger.core.viewmodel.ikey; import org.bouncycastle.openpgp.PGPException; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smackx.ikey.IkeyManager; import org.jivesoftware.smackx.ox.OpenPgpSecretKeyBackupPassphrase; import org.jivesoftware.smackx.ox.element.SecretkeyElement; import org.jivesoftware.smackx.ox.exception.InvalidBackupCodeException; import org.jivesoftware.smackx.pubsub.PubSubException; import org.mercury_im.messenger.core.connection.MercuryConnection; import org.mercury_im.messenger.core.connection.MercuryConnectionManager; import org.mercury_im.messenger.core.crypto.OpenPgpSecretKeyBackupPassphraseGenerator; import org.mercury_im.messenger.core.crypto.ikey.IkeyInitializer; import org.mercury_im.messenger.core.util.Optional; import org.mercury_im.messenger.core.viewmodel.MercuryViewModel; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; import javax.inject.Inject; import io.reactivex.Maybe; import io.reactivex.MaybeObserver; import io.reactivex.Single; import lombok.Getter; public class IkeySetupViewModel implements MercuryViewModel { private static final Logger LOGGER = Logger.getLogger(IkeySetupViewModel.class.getName()); private final MercuryConnectionManager connectionManager; private final IkeyInitializer ikeyInitializer; private IkeyManager ikeyManager; private SecretkeyElement secretkeyElement; @Getter private final OpenPgpSecretKeyBackupPassphrase backupCreationPassphrase; @Inject public IkeySetupViewModel(MercuryConnectionManager connectionManager, IkeyInitializer ikeyInitializer, OpenPgpSecretKeyBackupPassphraseGenerator passphraseGenerator) { this.connectionManager = connectionManager; this.ikeyInitializer = ikeyInitializer; this.backupCreationPassphrase = passphraseGenerator.generateBackupPassphrase(); } public void init(UUID accountId) { MercuryConnection connection = connectionManager.getConnection(accountId); ikeyManager = ikeyInitializer.initFor(connection); } public Single> fetchBackupElement() { return fetchMaybeBackupElement() .map(Optional::new) .toSingle(new Optional<>()); } private Maybe fetchMaybeBackupElement() { return new Maybe() { @Override protected void subscribeActual(MaybeObserver observer) { try { secretkeyElement = ikeyManager.fetchSecretIdentityKey(); if (secretkeyElement != null) { LOGGER.log(Level.INFO, "Found IKey backup element."); observer.onSuccess(secretkeyElement); } else { LOGGER.log(Level.INFO, "Ikey backup element is null."); observer.onComplete(); } } catch (PubSubException.NotALeafNodeException e) { LOGGER.log(Level.INFO, "Ikey backup node is not a LeafNode."); observer.onComplete(); } catch (InterruptedException | XMPPException.XMPPErrorException | SmackException.NotConnectedException | SmackException.NoResponseException e) { LOGGER.log(Level.INFO, "Error restoring Ikey backup", e); observer.onError(e); } } }; } public void generateIdentityKey() throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException { ikeyManager.generateIdentityKey(); } public void restoreBackup(OpenPgpSecretKeyBackupPassphrase passphrase) throws IOException, PGPException, InvalidBackupCodeException { ikeyManager.restoreSecretKeyBackup(secretkeyElement, passphrase); } }