can search openkeychain, retrieve & install & use keys from there
This commit is contained in:
@@ -62,6 +62,8 @@ public class ImportKeysActivity extends ActionBarActivity implements ActionBar.O
|
||||
+ "IMPORT_KEY_FROM_KEYSERVER";
|
||||
public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN = Constants.INTENT_PREFIX
|
||||
+ "IMPORT_KEY_FROM_KEY_SERVER_AND_RETURN";
|
||||
public static final String ACTION_IMPORT_KEY_FROM_KEYBASE = Constants.INTENT_PREFIX
|
||||
+ "IMPORT_KEY_FROM_KEYBASE";
|
||||
|
||||
// Actions for internal use only:
|
||||
public static final String ACTION_IMPORT_KEY_FROM_FILE = Constants.INTENT_PREFIX
|
||||
@@ -92,13 +94,15 @@ public class ImportKeysActivity extends ActionBarActivity implements ActionBar.O
|
||||
ImportKeysFileFragment.class,
|
||||
ImportKeysQrCodeFragment.class,
|
||||
ImportKeysClipboardFragment.class,
|
||||
ImportKeysNFCFragment.class
|
||||
ImportKeysNFCFragment.class,
|
||||
ImportKeysKeybaseFragment.class
|
||||
};
|
||||
private static final int NAV_SERVER = 0;
|
||||
private static final int NAV_FILE = 1;
|
||||
private static final int NAV_QR_CODE = 2;
|
||||
private static final int NAV_CLIPBOARD = 3;
|
||||
private static final int NAV_NFC = 4;
|
||||
private static final int NAV_KEYBASE = 5;
|
||||
|
||||
private int mCurrentNavPosition = -1;
|
||||
|
||||
@@ -236,6 +240,12 @@ public class ImportKeysActivity extends ActionBarActivity implements ActionBar.O
|
||||
// NOTE: this only displays the appropriate fragment, no actions are taken
|
||||
loadNavFragment(NAV_NFC, null);
|
||||
|
||||
// no immediate actions!
|
||||
startListFragment(savedInstanceState, null, null, null);
|
||||
} else if (ACTION_IMPORT_KEY_FROM_KEYBASE.equals(action)) {
|
||||
// NOTE: this only displays the appropriate fragment, no actions are taken
|
||||
loadNavFragment(NAV_KEYBASE, null);
|
||||
|
||||
// no immediate actions!
|
||||
startListFragment(savedInstanceState, null, null, null);
|
||||
} else {
|
||||
@@ -340,8 +350,8 @@ public class ImportKeysActivity extends ActionBarActivity implements ActionBar.O
|
||||
startListFragment(savedInstanceState, null, null, query);
|
||||
}
|
||||
|
||||
public void loadCallback(byte[] importData, Uri dataUri, String serverQuery, String keyServer) {
|
||||
mListFragment.loadNew(importData, dataUri, serverQuery, keyServer);
|
||||
public void loadCallback(byte[] importData, Uri dataUri, String serverQuery, String keyServer, String keybaseQuery) {
|
||||
mListFragment.loadNew(importData, dataUri, serverQuery, keyServer, keybaseQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -449,6 +459,31 @@ public class ImportKeysActivity extends ActionBarActivity implements ActionBar.O
|
||||
|
||||
// start service with intent
|
||||
startService(intent);
|
||||
} else if (mListFragment.getKeybaseQuery() != null) {
|
||||
// Send all information needed to service to query keys in other thread
|
||||
Intent intent = new Intent(this, KeychainIntentService.class);
|
||||
|
||||
intent.setAction(KeychainIntentService.ACTION_IMPORT_KEYBASE_KEYS);
|
||||
|
||||
// fill values for this action
|
||||
Bundle data = new Bundle();
|
||||
|
||||
// get selected key entries
|
||||
ArrayList<ImportKeysListEntry> selectedEntries = mListFragment.getSelectedData();
|
||||
data.putParcelableArrayList(KeychainIntentService.DOWNLOAD_KEY_LIST, selectedEntries);
|
||||
|
||||
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
|
||||
|
||||
// Create a new Messenger for the communication back
|
||||
Messenger messenger = new Messenger(saveHandler);
|
||||
intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
|
||||
|
||||
// show progress dialog
|
||||
saveHandler.showProgressDialog(this);
|
||||
|
||||
// start service with intent
|
||||
startService(intent);
|
||||
|
||||
} else {
|
||||
AppMsg.makeText(this, R.string.error_nothing_import, AppMsg.STYLE_ALERT).show();
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public class ImportKeysClipboardFragment extends Fragment {
|
||||
return;
|
||||
}
|
||||
}
|
||||
mImportActivity.loadCallback(sendText.getBytes(), null, null, null);
|
||||
mImportActivity.loadCallback(sendText.getBytes(), null, null, null, null);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ public class ImportKeysFileFragment extends Fragment {
|
||||
if (resultCode == Activity.RESULT_OK && data != null) {
|
||||
|
||||
// load data
|
||||
mImportActivity.loadCallback(null, data.getData(), null, null);
|
||||
mImportActivity.loadCallback(null, data.getData(), null, null, null);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.beardedhen.androidbootstrap.BootstrapButton;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
/**
|
||||
* Import public keys from the Keybase.io directory. First cut: just raw search.
|
||||
* TODO: make a pick list of the people you’re following on keybase
|
||||
*/
|
||||
public class ImportKeysKeybaseFragment extends Fragment {
|
||||
|
||||
private ImportKeysActivity mImportActivity;
|
||||
private BootstrapButton mSearchButton;
|
||||
private EditText mQueryEditText;
|
||||
|
||||
public static final String ARG_QUERY = "query";
|
||||
public static final String ARG_DISABLE_QUERY_EDIT = "disable_query_edit";
|
||||
|
||||
/**
|
||||
* Creates new instance of this fragment
|
||||
*/
|
||||
public static ImportKeysKeybaseFragment newInstance() {
|
||||
ImportKeysKeybaseFragment frag = new ImportKeysKeybaseFragment();
|
||||
|
||||
Bundle args = new Bundle();
|
||||
frag.setArguments(args);
|
||||
|
||||
return frag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inflate the layout for this fragment
|
||||
*/
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.import_keys_keybase_fragment, container, false);
|
||||
|
||||
mQueryEditText = (EditText) view.findViewById(R.id.import_keybase_query);
|
||||
|
||||
mSearchButton = (BootstrapButton) view.findViewById(R.id.import_keybase_search);
|
||||
mSearchButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
String query = mQueryEditText.getText().toString();
|
||||
search(query);
|
||||
|
||||
// close keyboard after pressing search
|
||||
InputMethodManager imm =
|
||||
(InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
imm.hideSoftInputFromWindow(mQueryEditText.getWindowToken(), 0);
|
||||
}
|
||||
});
|
||||
|
||||
mQueryEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
|
||||
@Override
|
||||
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
|
||||
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
|
||||
String query = mQueryEditText.getText().toString();
|
||||
search(query);
|
||||
|
||||
// Don't return true to let the keyboard close itself after pressing search
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
mImportActivity = (ImportKeysActivity) getActivity();
|
||||
|
||||
// set displayed values
|
||||
if (getArguments() != null) {
|
||||
if (getArguments().containsKey(ARG_QUERY)) {
|
||||
String query = getArguments().getString(ARG_QUERY);
|
||||
mQueryEditText.setText(query, TextView.BufferType.EDITABLE);
|
||||
}
|
||||
|
||||
if (getArguments().getBoolean(ARG_DISABLE_QUERY_EDIT, false)) {
|
||||
mQueryEditText.setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void search(String query) {
|
||||
mImportActivity.loadCallback(null, null, null, null, query);
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ import org.sufficientlysecure.keychain.helper.Preferences;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.AsyncTaskResultWrapper;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListKeybaseLoader;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListLoader;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListServerLoader;
|
||||
import org.sufficientlysecure.keychain.util.InputData;
|
||||
@@ -60,9 +61,11 @@ public class ImportKeysListFragment extends ListFragment implements
|
||||
private Uri mDataUri;
|
||||
private String mServerQuery;
|
||||
private String mKeyServer;
|
||||
private String mKeybaseQuery;
|
||||
|
||||
private static final int LOADER_ID_BYTES = 0;
|
||||
private static final int LOADER_ID_SERVER_QUERY = 1;
|
||||
private static final int LOADER_ID_KEYBASE = 2;
|
||||
|
||||
public byte[] getKeyBytes() {
|
||||
return mKeyBytes;
|
||||
@@ -76,6 +79,10 @@ public class ImportKeysListFragment extends ListFragment implements
|
||||
return mServerQuery;
|
||||
}
|
||||
|
||||
public String getKeybaseQuery() {
|
||||
return mKeybaseQuery;
|
||||
}
|
||||
|
||||
public String getKeyServer() {
|
||||
return mKeyServer;
|
||||
}
|
||||
@@ -148,6 +155,16 @@ public class ImportKeysListFragment extends ListFragment implements
|
||||
// give arguments to onCreateLoader()
|
||||
getLoaderManager().initLoader(LOADER_ID_SERVER_QUERY, null, this);
|
||||
}
|
||||
|
||||
if (mKeybaseQuery != null) {
|
||||
// Start out with a progress indicator.
|
||||
setListShown(false);
|
||||
|
||||
// Prepare the loader. Either re-connect with an existing one,
|
||||
// or start a new one.
|
||||
// give arguments to onCreateLoader()
|
||||
getLoaderManager().initLoader(LOADER_ID_KEYBASE, null, this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -157,16 +174,18 @@ public class ImportKeysListFragment extends ListFragment implements
|
||||
// Select checkbox!
|
||||
// Update underlying data and notify adapter of change. The adapter will
|
||||
// update the view automatically.
|
||||
|
||||
ImportKeysListEntry entry = mAdapter.getItem(position);
|
||||
entry.setSelected(!entry.isSelected());
|
||||
mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void loadNew(byte[] keyBytes, Uri dataUri, String serverQuery, String keyServer) {
|
||||
public void loadNew(byte[] keyBytes, Uri dataUri, String serverQuery, String keyServer, String keybaseQuery) {
|
||||
mKeyBytes = keyBytes;
|
||||
mDataUri = dataUri;
|
||||
mServerQuery = serverQuery;
|
||||
mKeyServer = keyServer;
|
||||
mKeybaseQuery = keybaseQuery;
|
||||
|
||||
if (mKeyBytes != null || mDataUri != null) {
|
||||
// Start out with a progress indicator.
|
||||
@@ -181,11 +200,18 @@ public class ImportKeysListFragment extends ListFragment implements
|
||||
|
||||
getLoaderManager().restartLoader(LOADER_ID_SERVER_QUERY, null, this);
|
||||
}
|
||||
|
||||
if (mKeybaseQuery != null) {
|
||||
// Start out with a progress indicator.
|
||||
setListShown(false);
|
||||
|
||||
getLoaderManager().restartLoader(LOADER_ID_KEYBASE, null, this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>>
|
||||
onCreateLoader(int id, Bundle args) {
|
||||
onCreateLoader(int id, Bundle args) {
|
||||
switch (id) {
|
||||
case LOADER_ID_BYTES: {
|
||||
InputData inputData = getInputData(mKeyBytes, mDataUri);
|
||||
@@ -194,6 +220,9 @@ public class ImportKeysListFragment extends ListFragment implements
|
||||
case LOADER_ID_SERVER_QUERY: {
|
||||
return new ImportKeysListServerLoader(getActivity(), mServerQuery, mKeyServer);
|
||||
}
|
||||
case LOADER_ID_KEYBASE: {
|
||||
return new ImportKeysListKeybaseLoader(getActivity(), mKeybaseQuery);
|
||||
}
|
||||
|
||||
default:
|
||||
return null;
|
||||
@@ -248,7 +277,7 @@ public class ImportKeysListFragment extends ListFragment implements
|
||||
if (error == null) {
|
||||
AppMsg.makeText(
|
||||
getActivity(), getResources().getQuantityString(R.plurals.keys_found,
|
||||
mAdapter.getCount(), mAdapter.getCount()),
|
||||
mAdapter.getCount(), mAdapter.getCount()),
|
||||
AppMsg.STYLE_INFO
|
||||
).show();
|
||||
} else if (error instanceof KeyServer.InsufficientQuery) {
|
||||
@@ -263,6 +292,19 @@ public class ImportKeysListFragment extends ListFragment implements
|
||||
}
|
||||
break;
|
||||
|
||||
case LOADER_ID_KEYBASE:
|
||||
|
||||
if (error == null) {
|
||||
AppMsg.makeText(
|
||||
getActivity(), getResources().getQuantityString(R.plurals.keys_found,
|
||||
mAdapter.getCount(), mAdapter.getCount()),
|
||||
AppMsg.STYLE_INFO
|
||||
).show();
|
||||
} else if (error instanceof KeyServer.QueryException) {
|
||||
AppMsg.makeText(getActivity(), R.string.error_keyserver_query,
|
||||
AppMsg.STYLE_ALERT).show();
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -279,6 +321,10 @@ public class ImportKeysListFragment extends ListFragment implements
|
||||
// Clear the data in the adapter.
|
||||
mAdapter.clear();
|
||||
break;
|
||||
case LOADER_ID_KEYBASE:
|
||||
// Clear the data in the adapter.
|
||||
mAdapter.clear();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ public class ImportKeysQrCodeFragment extends Fragment {
|
||||
|
||||
// is this a full key encoded as qr code?
|
||||
if (scannedContent.startsWith("-----BEGIN PGP")) {
|
||||
mImportActivity.loadCallback(scannedContent.getBytes(), null, null, null);
|
||||
mImportActivity.loadCallback(scannedContent.getBytes(), null, null, null, null);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ public class ImportKeysQrCodeFragment extends Fragment {
|
||||
for (String in : mScannedContent) {
|
||||
result += in;
|
||||
}
|
||||
mImportActivity.loadCallback(result.getBytes(), null, null, null);
|
||||
mImportActivity.loadCallback(result.getBytes(), null, null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ public class ImportKeysServerFragment extends Fragment {
|
||||
}
|
||||
|
||||
private void search(String query, String keyServer) {
|
||||
mImportActivity.loadCallback(null, null, query, keyServer);
|
||||
mImportActivity.loadCallback(null, null, query, keyServer, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
|
||||
* Constructor for later querying from keyserver
|
||||
*/
|
||||
public ImportKeysListEntry() {
|
||||
// keys from keyserver are always public keys
|
||||
// keys from keyserver are always public keys; from keybase too
|
||||
secretKey = false;
|
||||
// do not select by default
|
||||
mSelected = false;
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.ui.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.util.KeyServer;
|
||||
import org.sufficientlysecure.keychain.util.KeybaseKeyServer;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ImportKeysListKeybaseLoader
|
||||
extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> {
|
||||
Context mContext;
|
||||
|
||||
String mKeybaseQuery;
|
||||
|
||||
private ArrayList<ImportKeysListEntry> mEntryList = new ArrayList<ImportKeysListEntry>();
|
||||
private AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> mEntryListWrapper;
|
||||
|
||||
public ImportKeysListKeybaseLoader(Context context, String keybaseQuery) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
mKeybaseQuery = keybaseQuery;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() {
|
||||
|
||||
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, null);
|
||||
|
||||
if (mKeybaseQuery == null) {
|
||||
Log.e(Constants.TAG, "mKeybaseQery is null!");
|
||||
return mEntryListWrapper;
|
||||
}
|
||||
|
||||
queryServer(mKeybaseQuery);
|
||||
|
||||
return mEntryListWrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReset() {
|
||||
super.onReset();
|
||||
|
||||
// Ensure the loader is stopped
|
||||
onStopLoading();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
forceLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStopLoading() {
|
||||
cancelLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliverResult(AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> data) {
|
||||
super.deliverResult(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query keybase
|
||||
*/
|
||||
private void queryServer(String query) {
|
||||
|
||||
KeybaseKeyServer server = new KeybaseKeyServer();
|
||||
try {
|
||||
ArrayList<ImportKeysListEntry> searchResult = server.search(query);
|
||||
|
||||
mEntryList.clear();
|
||||
|
||||
mEntryList.addAll(searchResult);
|
||||
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, null);
|
||||
} catch (KeyServer.InsufficientQuery e) {
|
||||
Log.e(Constants.TAG, "InsufficientQuery", e);
|
||||
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e);
|
||||
} catch (KeyServer.QueryException e) {
|
||||
Log.e(Constants.TAG, "QueryException", e);
|
||||
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e);
|
||||
} catch (KeyServer.TooManyResponses e) {
|
||||
Log.e(Constants.TAG, "TooManyResponses", e);
|
||||
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user