/* * Copyright (C) 2017 Vincent Breitmoser * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.sufficientlysecure.keychain.ui; import android.content.Context; import android.os.Bundle; import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.Loader; import org.sufficientlysecure.keychain.provider.KeyRepository; import org.sufficientlysecure.keychain.ui.CreateSecurityTokenImportFragment.StatusLine; import org.sufficientlysecure.keychain.ui.PublicKeyRetrievalLoader.KeyRetrievalResult; import org.sufficientlysecure.keychain.ui.PublicKeyRetrievalLoader.KeyserverRetrievalLoader; import org.sufficientlysecure.keychain.ui.PublicKeyRetrievalLoader.LocalKeyLookupLoader; import org.sufficientlysecure.keychain.ui.PublicKeyRetrievalLoader.UriKeyRetrievalLoader; class CreateSecurityTokenImportPresenter { private static final int LOADER_LOCAL = 0; private static final int LOADER_URI = 1; private static final int LOADER_KEYSERVER = 2; private Context context; private byte[][] tokenFingerprints; private byte[] tokenAid; private double tokenVersion; private String tokenUserId; private final String tokenUrl; private LoaderManager loaderManager; private CreateSecurityTokenImportMvpView view; private boolean searchedLocally; private boolean searchedAtUri; private boolean searchedKeyservers; private byte[] importKeyData; private Long masterKeyId; public CreateSecurityTokenImportPresenter(Context context, byte[] tokenFingerprints, byte[] tokenAid, String tokenUserId, String tokenUrl, LoaderManager loaderManager) { this.context = context.getApplicationContext(); this.tokenAid = tokenAid; this.tokenUserId = tokenUserId; this.tokenUrl = tokenUrl; this.loaderManager = loaderManager; if (tokenFingerprints.length % 20 != 0) { throw new IllegalArgumentException("fingerprints must be multiple of 20 bytes!"); } this.tokenFingerprints = new byte[tokenFingerprints.length / 20][]; for (int i = 0; i < tokenFingerprints.length / 20; i++) { this.tokenFingerprints[i] = new byte[20]; System.arraycopy(tokenFingerprints, i*20, this.tokenFingerprints[i], 0, 20); } } public void setView(CreateSecurityTokenImportMvpView view) { this.view = view; } public void onActivityCreated() { continueSearch(); } private void continueSearchAfterError() { view.statusLineError(); continueSearch(); } private void continueSearch() { if (!searchedLocally) { view.statusLineAdd(StatusLine.SEARCH_LOCAL); loaderManager.restartLoader(LOADER_LOCAL, null, loaderCallbacks); return; } if (!searchedAtUri) { view.statusLineAdd(StatusLine.SEARCH_URI); loaderManager.restartLoader(LOADER_URI, null, loaderCallbacks); return; } if (!searchedKeyservers) { view.statusLineAdd(StatusLine.SEARCH_KEYSERVER); loaderManager.restartLoader(LOADER_KEYSERVER, null, loaderCallbacks); return; } view.showActionRetryOrFromFile(); } private LoaderCallbacks loaderCallbacks = new LoaderCallbacks() { @Override public Loader onCreateLoader(int id, Bundle args) { switch (id) { case LOADER_LOCAL: return new LocalKeyLookupLoader(context, tokenFingerprints); case LOADER_URI: return new UriKeyRetrievalLoader(context, tokenUrl, tokenFingerprints); case LOADER_KEYSERVER: return new KeyserverRetrievalLoader(context, tokenFingerprints[0]); } throw new IllegalArgumentException("called with unknown loader id!"); } @Override public void onLoadFinished(Loader loader, KeyRetrievalResult data) { switch (loader.getId()) { case LOADER_LOCAL: { searchedLocally = true; break; } case LOADER_URI: { searchedAtUri = true; break; } case LOADER_KEYSERVER: { searchedKeyservers = true; break; } default: { throw new IllegalArgumentException("called with unknown loader id!"); } } if (data.isSuccess()) { processResult(data); } else { continueSearchAfterError(); } } @Override public void onLoaderReset(Loader loader) { } }; private void processResult(KeyRetrievalResult result) { view.statusLineOk(); byte[] importKeyData = result.getKeyData(); Long masterKeyId = result.getMasterKeyId(); if (importKeyData != null && masterKeyId != null) { view.showActionImport(); this.importKeyData = importKeyData; this.masterKeyId = masterKeyId; return; } if (masterKeyId != null) { this.masterKeyId = masterKeyId; view.statusLineAdd(StatusLine.TOKEN_CHECK); view.operationPromote(masterKeyId, tokenAid); return; } throw new IllegalArgumentException("Method can only be called with successful result!"); } void onClickImport() { view.statusLineAdd(StatusLine.IMPORT); view.hideAction(); view.operationImportKey(importKeyData); } void onImportSuccess() { view.statusLineOk(); view.statusLineAdd(StatusLine.TOKEN_PROMOTE); view.operationPromote(masterKeyId, tokenAid); } void onImportError() { view.statusLineError(); } void onPromoteSuccess() { view.statusLineOk(); view.showActionViewKey(); } void onPromoteError() { view.statusLineError(); } void onClickRetry() { searchedLocally = false; searchedAtUri = false; searchedKeyservers = false; view.hideAction(); view.resetStatusLines(); continueSearch(); } void onClickViewKey() { view.finishAndShowKey(masterKeyId); } public void onClickResetToken() { } interface CreateSecurityTokenImportMvpView { void statusLineAdd(StatusLine statusLine); void statusLineOk(); void statusLineError(); void resetStatusLines(); void showActionImport(); void showActionViewKey(); void showActionRetryOrFromFile(); void hideAction(); void operationImportKey(byte[] importKeyData); void operationPromote(long masterKeyId, byte[] cardAid); void finishAndShowKey(long masterKeyId); } }