diff options
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain')
9 files changed, 304 insertions, 358 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 2ffb7227e..930c1fc26 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -18,6 +18,11 @@ package org.sufficientlysecure.keychain.ui; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + import android.animation.ArgbEvaluator; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; @@ -55,7 +60,6 @@ import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; - import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; @@ -68,9 +72,10 @@ import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.ImportKeyringParcel; -import org.sufficientlysecure.keychain.ui.linked.LinkedIdWizard; +import org.sufficientlysecure.keychain.ui.ViewKeyFragment.PostponeType; import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity; import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper; +import org.sufficientlysecure.keychain.ui.linked.LinkedIdWizard; import org.sufficientlysecure.keychain.ui.util.FormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State; @@ -84,9 +89,6 @@ import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.NfcHelper; import org.sufficientlysecure.keychain.util.Preferences; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; public class ViewKeyActivity extends BaseNfcActivity implements LoaderManager.LoaderCallbacks<Cursor>, @@ -102,6 +104,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements static final int REQUEST_DELETE = 4; public static final String EXTRA_DISPLAY_RESULT = "display_result"; + public static final String EXTRA_LINKED_TRANSITION = "linked_transition"; ProviderHelper mProviderHelper; @@ -294,9 +297,15 @@ public class ViewKeyActivity extends BaseNfcActivity implements return; } + boolean linkedTransition = getIntent().getBooleanExtra(EXTRA_LINKED_TRANSITION, false); + if (linkedTransition && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + postponeEnterTransition(); + } + FragmentManager manager = getSupportFragmentManager(); // Create an instance of the fragment - final ViewKeyFragment frag = ViewKeyFragment.newInstance(mDataUri); + final ViewKeyFragment frag = ViewKeyFragment.newInstance(mDataUri, + linkedTransition ? PostponeType.LINKED : PostponeType.NONE); manager.beginTransaction() .replace(R.id.view_key_fragment, frag) .commit(); @@ -362,6 +371,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements Intent intent = new Intent(this, LinkedIdWizard.class); intent.setData(mDataUri); startActivity(intent); + finish(); return true; } case R.id.menu_key_view_edit: { @@ -418,7 +428,7 @@ public class ViewKeyActivity extends BaseNfcActivity implements private void certifyImmediate() { Intent intent = new Intent(this, CertifyKeyActivity.class); - intent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{mMasterKeyId}); + intent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[] { mMasterKeyId }); startActivityForResult(intent, REQUEST_CERTIFY); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java index 32e2d2def..7be695de0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java @@ -18,7 +18,11 @@ package org.sufficientlysecure.keychain.ui; + import java.io.IOException; +import java.util.List; + +import android.annotation.TargetApi; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -26,6 +30,7 @@ import android.database.Cursor; import android.graphics.Bitmap; import android.net.Uri; import android.os.Build; +import android.os.Build.VERSION_CODES; import android.os.Bundle; import android.os.Handler; import android.provider.ContactsContract; @@ -39,17 +44,20 @@ import android.transition.TransitionInflater; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.ViewTreeObserver.OnPreDrawListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; +import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; -import android.widget.*; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; -import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsAdapter; import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsAdapter; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment; import org.sufficientlysecure.keychain.ui.linked.LinkedIdViewFragment; @@ -58,22 +66,20 @@ import org.sufficientlysecure.keychain.util.ContactHelper; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Preferences; -import java.util.List; - public class ViewKeyFragment extends LoaderFragment implements LoaderManager.LoaderCallbacks<Cursor> { public static final String ARG_DATA_URI = "uri"; + public static final String ARG_POSTPONE_TYPE = "postpone_type"; private ListView mUserIds; //private ListView mLinkedSystemContact; - boolean mIsSecret = false; + enum PostponeType { + NONE, LINKED; + } - CardView mSystemContactCard; - LinearLayout mSystemContactLayout; - ImageView mSystemContactPicture; - TextView mSystemContactName; + boolean mIsSecret = false; private static final int LOADER_ID_UNIFIED = 0; private static final int LOADER_ID_USER_IDS = 1; @@ -89,6 +95,13 @@ public class ViewKeyFragment extends LoaderFragment implements private LinkedIdsAdapter mLinkedIdsAdapter; private Uri mDataUri; + private PostponeType mPostponeType; + + private CardView mSystemContactCard; + private LinearLayout mSystemContactLayout; + private ImageView mSystemContactPicture; + private TextView mSystemContactName; + private ListView mLinkedIds; private CardView mLinkedIdsCard; private byte[] mFingerprint; @@ -97,10 +110,11 @@ public class ViewKeyFragment extends LoaderFragment implements /** * Creates new instance of this fragment */ - public static ViewKeyFragment newInstance(Uri dataUri) { + public static ViewKeyFragment newInstance(Uri dataUri, PostponeType postponeType) { ViewKeyFragment frag = new ViewKeyFragment(); Bundle args = new Bundle(); args.putParcelable(ARG_DATA_URI, dataUri); + args.putInt(ARG_POSTPONE_TYPE, postponeType.ordinal()); frag.setArguments(args); @@ -271,6 +285,7 @@ public class ViewKeyFragment extends LoaderFragment implements super.onActivityCreated(savedInstanceState); Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); + mPostponeType = PostponeType.values()[getArguments().getInt(ARG_POSTPONE_TYPE, 0)]; if (dataUri == null) { Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); getActivity().finish(); @@ -325,10 +340,10 @@ public class ViewKeyFragment extends LoaderFragment implements @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { - setContentShown(false); switch (id) { case LOADER_ID_UNIFIED: { + setContentShown(false, false); Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(mDataUri); return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); } @@ -390,6 +405,7 @@ public class ViewKeyFragment extends LoaderFragment implements mIsSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0; mFingerprint = data.getBlob(INDEX_FINGERPRINT); + long masterKeyId = data.getLong(INDEX_MASTER_KEY_ID); // load user ids after we know if it's a secret key mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0, !mIsSecret, null); @@ -403,13 +419,6 @@ public class ViewKeyFragment extends LoaderFragment implements getLoaderManager().initLoader(LOADER_ID_LINKED_IDS, null, this); } - long masterKeyId = data.getLong(INDEX_MASTER_KEY_ID); - // we need to load linked contact here to prevent lag introduced by loader - // for the linked contact - long contactId = ContactHelper.findContactId( - getActivity().getContentResolver(), - masterKeyId); - loadLinkedSystemContact(contactId); Bundle linkedContactData = new Bundle(); linkedContactData.putLong(LOADER_EXTRA_LINKED_CONTACT_MASTER_KEY_ID, masterKeyId); @@ -423,6 +432,7 @@ public class ViewKeyFragment extends LoaderFragment implements } case LOADER_ID_USER_IDS: { + setContentShown(true, false); mUserIdsAdapter.swapCursor(data); break; } @@ -430,6 +440,17 @@ public class ViewKeyFragment extends LoaderFragment implements case LOADER_ID_LINKED_IDS: { mLinkedIdsAdapter.swapCursor(data); mLinkedIdsCard.setVisibility(mLinkedIdsAdapter.getCount() > 0 ? View.VISIBLE : View.GONE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mPostponeType == PostponeType.LINKED) { + mLinkedIdsCard.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() { + @TargetApi(VERSION_CODES.LOLLIPOP) + @Override + public boolean onPreDraw() { + mLinkedIdsCard.getViewTreeObserver().removeOnPreDrawListener(this); + getActivity().startPostponedEnterTransition(); + return true; + } + }); + } break; } @@ -442,7 +463,6 @@ public class ViewKeyFragment extends LoaderFragment implements } } - setContentShown(true); } /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/LinkedIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/LinkedIdsAdapter.java index 805666bb2..5cf0e6e08 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/LinkedIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/LinkedIdsAdapter.java @@ -23,6 +23,7 @@ import android.app.Activity; import android.content.Context; import android.database.Cursor; import android.net.Uri; +import android.os.Build; import android.support.v4.content.CursorLoader; import android.util.Log; import android.view.LayoutInflater; @@ -135,6 +136,10 @@ public class LinkedIdsAdapter extends UserAttributesAdapter { UriAttribute id = getItemAtPosition(cursor); holder.setData(mContext, id); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + view.setTransitionName(id.mUri.toString()); + } + } public UriAttribute getItemAtPosition(Cursor cursor) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateGithubFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateGithubFragment.java index b59166721..eeb2ad116 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateGithubFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateGithubFragment.java @@ -28,21 +28,39 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.URI; import java.net.URL; - +import java.util.Random; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnDismissListener; +import android.content.Intent; +import android.net.Uri; import android.os.AsyncTask; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.v4.app.ActivityOptionsCompat; +import android.support.v4.app.FragmentActivity; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; +import android.webkit.CookieManager; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.ImageView; +import android.widget.TextView; import android.widget.ViewAnimator; import javax.net.ssl.HttpsURLConnection; import org.json.JSONException; import org.json.JSONObject; +import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.BuildConfig; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; @@ -50,7 +68,9 @@ import org.sufficientlysecure.keychain.linked.LinkedAttribute; import org.sufficientlysecure.keychain.linked.resources.GithubResource; import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; +import org.sufficientlysecure.keychain.ui.ViewKeyActivity; import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment; import org.sufficientlysecure.keychain.ui.widget.StatusIndicator; import org.sufficientlysecure.keychain.util.Log; @@ -65,6 +85,8 @@ public class LinkedIdCreateGithubFragment extends CryptoOperationFragment<SaveKe byte[] mFingerprint; long mMasterKeyId; private SaveKeyringParcel mSaveKeyringParcel; + private TextView mLinkedIdTitle, mLinkedIdComment; + private boolean mFinishOnStop; public static LinkedIdCreateGithubFragment newInstance() { return new LinkedIdCreateGithubFragment(); @@ -84,10 +106,28 @@ public class LinkedIdCreateGithubFragment extends CryptoOperationFragment<SaveKe mStatus2 = (StatusIndicator) view.findViewById(R.id.linked_status_step2); mStatus3 = (StatusIndicator) view.findViewById(R.id.linked_status_step3); + ((ImageView) view.findViewById(R.id.linked_id_type_icon)).setImageResource(R.drawable.linked_github); + ((ImageView) view.findViewById(R.id.linked_id_certified_icon)).setImageResource(R.drawable.octo_link_24dp); + mLinkedIdTitle = (TextView) view.findViewById(R.id.linked_id_title); + mLinkedIdComment = (TextView) view.findViewById(R.id.linked_id_comment); + + view.findViewById(R.id.back_button).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + LinkedIdWizard activity = (LinkedIdWizard) getActivity(); + if (activity == null) { + return; + } + activity.loadFragment(null, null, LinkedIdWizard.FRAG_ACTION_TO_LEFT); + } + }); + view.findViewById(R.id.button_send).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - step1GetOAuthToken(); + step1GetOAuthCode(); + // for animation testing + // onCryptoOperationSuccess(null); } }); @@ -95,48 +135,62 @@ public class LinkedIdCreateGithubFragment extends CryptoOperationFragment<SaveKe } @Override - public void onResume() { - super.onResume(); + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); LinkedIdWizard wizard = (LinkedIdWizard) getActivity(); mFingerprint = wizard.mFingerprint; mMasterKeyId = wizard.mMasterKeyId; + } + + private void step1GetOAuthCode() { - final String oAuthCode = wizard.oAuthGetCode(); - final String oAuthState = wizard.oAuthGetState(); - if (oAuthCode == null) { + mStatus1.setDisplayedChild(1); + mStatus2.setDisplayedChild(0); + mStatus3.setDisplayedChild(0); + + mButtonContainer.setDisplayedChild(1); + + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + oAuthRequest("github.com/login/oauth/authorize", "7a011b66275f244d3f21", "gist"); + } + }, 300); + + } + + private void step1GetOAuthToken() { + + if (mOAuthCode == null) { Log.d(Constants.TAG, "no code"); return; } - final String gistText = GithubResource.generate(wizard, mFingerprint); + Activity activity = getActivity(); + if (activity == null) { + return; + } + + // this is only good once! + final String oAuthCode = mOAuthCode, oAuthState = mOAuthState; + mOAuthCode = null; + mOAuthState = null; - Log.d(Constants.TAG, "got code: " + oAuthCode); + final String gistText = GithubResource.generate(activity, mFingerprint); new AsyncTask<Void,Void,JSONObject>() { @Override protected JSONObject doInBackground(Void... dummy) { try { - long timer = System.currentTimeMillis(); - JSONObject params = new JSONObject(); params.put("client_id", "7a011b66275f244d3f21"); params.put("client_secret", "eaced8a6655719d8c6848396de97b3f5d7a89fec"); params.put("code", oAuthCode); params.put("state", oAuthState); - JSONObject result = jsonHttpRequest("https://github.com/login/oauth/access_token", params, null); - - // ux flow: this operation should take at last a second - timer = System.currentTimeMillis() -timer; - if (timer < 1000) try { - Thread.sleep(1000 -timer); - } catch (InterruptedException e) { - // never mind - } - - return result; + return jsonHttpRequest("https://github.com/login/oauth/access_token", params, null); } catch (IOException e) { Log.e(Constants.TAG, "error in request", e); @@ -165,29 +219,6 @@ public class LinkedIdCreateGithubFragment extends CryptoOperationFragment<SaveKe } - private void step1GetOAuthToken() { - - mStatus1.setDisplayedChild(1); - mStatus2.setDisplayedChild(0); - mStatus3.setDisplayedChild(0); - - mButtonContainer.setDisplayedChild(1); - - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - - LinkedIdWizard wizard = (LinkedIdWizard) getActivity(); - if (wizard == null) { - return; - } - wizard.oAuthRequest("github.com/login/oauth/authorize", "7a011b66275f244d3f21", "gist"); - - } - }, 250); - - } - private void step2PostGist(final String accessToken, final String gistText) { mStatus2.setDisplayedChild(1); @@ -249,6 +280,13 @@ public class LinkedIdCreateGithubFragment extends CryptoOperationFragment<SaveKe URI uri = URI.create("https://gist.github.com/" + gistLogin + "/" + gistId); GithubResource resource = GithubResource.create(uri); + View linkedItem = mButtonContainer.getChildAt(2); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + linkedItem.setTransitionName(resource.toUri().toString()); + } + + revokeToken(accessToken); + mStatus2.setDisplayedChild(2); step3EditKey(resource); @@ -262,8 +300,35 @@ public class LinkedIdCreateGithubFragment extends CryptoOperationFragment<SaveKe } + private void revokeToken(final String token) { + + new AsyncTask<Void,Void,Void>() { + @Override + protected Void doInBackground(Void... dummy) { + try { + HttpsURLConnection nection = (HttpsURLConnection) new URL( + "https://api.github.com/applications/7a011b66275f244d3f21/tokens/" + token) + .openConnection(); + nection.setRequestMethod("DELETE"); + nection.connect(); + } catch (IOException e) { + // nvm + } + return null; + } + }.execute(); + + } + private void step3EditKey(final GithubResource resource) { + // set item data while we're there + { + Context context = getActivity(); + mLinkedIdTitle.setText(resource.getDisplayTitle(context)); + mLinkedIdComment.setText(resource.getDisplayComment(context)); + } + mStatus3.setDisplayedChild(1); new Handler().postDelayed(new Runnable() { @@ -291,6 +356,42 @@ public class LinkedIdCreateGithubFragment extends CryptoOperationFragment<SaveKe @Override public void onCryptoOperationSuccess(EditKeyResult result) { mStatus3.setDisplayedChild(2); + + mButtonContainer.getInAnimation().setDuration(750); + mButtonContainer.setDisplayedChild(2); + + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + FragmentActivity activity = getActivity(); + Intent intent = new Intent(activity, ViewKeyActivity.class); + intent.setData(KeyRings.buildGenericKeyRingUri(mMasterKeyId)); + // intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + intent.putExtra(ViewKeyActivity.EXTRA_LINKED_TRANSITION, true); + View linkedItem = mButtonContainer.getChildAt(2); + + Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation( + activity, linkedItem, linkedItem.getTransitionName()).toBundle(); + activity.startActivity(intent, options); + mFinishOnStop = true; + } else { + activity.startActivity(intent); + activity.finish(); + } + } + }, 1000); + } + + @Override + public void onStop() { + super.onStop(); + if (mFinishOnStop) { + Activity activity = getActivity(); + activity.setResult(Activity.RESULT_OK); + activity.finish(); + } } @Override @@ -305,6 +406,75 @@ public class LinkedIdCreateGithubFragment extends CryptoOperationFragment<SaveKe mStatus3.setDisplayedChild(3); } + private String mOAuthCode, mOAuthState; + + @SuppressLint("SetJavaScriptEnabled") // trusted https website, it's ok + public void oAuthRequest(String hostAndPath, String clientId, String scope) { + + Activity activity = getActivity(); + if (activity == null) { + return; + } + + byte[] buf = new byte[16]; + new Random().nextBytes(buf); + mOAuthState = new String(Hex.encode(buf)); + + final Dialog auth_dialog = new Dialog(activity); + auth_dialog.setContentView(R.layout.oauth_webview); + WebView web = (WebView) auth_dialog.findViewById(R.id.web_view); + web.getSettings().setSaveFormData(false); + web.setWebViewClient(new WebViewClient() { + + boolean authComplete = false; + + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + Uri uri = Uri.parse(url); + if ("oauth-openkeychain".equals(uri.getScheme()) && !authComplete) { + authComplete = true; + + if (uri.getQueryParameter("error") != null) { + Log.i(Constants.TAG, "ACCESS_DENIED_HERE"); + auth_dialog.dismiss(); + return true; + } + + // check if mOAuthState == queryParam[state] + mOAuthCode = uri.getQueryParameter("code"); + + Log.d(Constants.TAG, "got ok response, code is " + mOAuthCode); + + CookieManager cookieManager = CookieManager.getInstance(); + // noinspection deprecation (replacement is api lvl 21) + cookieManager.removeAllCookie(); + + auth_dialog.dismiss(); + return true; + } + return false; + } + + }); + + auth_dialog.setTitle("GitHub Authorization"); + auth_dialog.setCancelable(true); + auth_dialog.setOnDismissListener(new OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + step1GetOAuthToken(); + } + }); + auth_dialog.show(); + + web.loadUrl("https://" + hostAndPath + + "?client_id=" + clientId + + "&scope=" + scope + + "&redirect_uri=oauth-openkeychain://linked/" + + "&state=" + mOAuthState); + + } + private static JSONObject jsonHttpRequest(String url, JSONObject params, String accessToken) throws IOException { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateGithubStep1Fragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateGithubStep1Fragment.java deleted file mode 100644 index b166b3e4f..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateGithubStep1Fragment.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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.linked; - -import android.os.AsyncTask; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.EditText; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.util.Notify; - - -public class LinkedIdCreateGithubStep1Fragment extends Fragment { - - LinkedIdWizard mLinkedIdWizard; - - EditText mEditHandle; - - public static LinkedIdCreateGithubStep1Fragment newInstance() { - LinkedIdCreateGithubStep1Fragment frag = new LinkedIdCreateGithubStep1Fragment(); - - Bundle args = new Bundle(); - frag.setArguments(args); - - return frag; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - mLinkedIdWizard = (LinkedIdWizard) getActivity(); - - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - final View view = inflater.inflate(R.layout.linked_create_github_fragment_step1, container, false); - - view.findViewById(R.id.next_button).setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - - final String handle = mEditHandle.getText().toString(); - - new AsyncTask<Void,Void,Boolean>() { - - @Override - protected Boolean doInBackground(Void... params) { - return true; // return checkHandle(handle); - } - - @Override - protected void onPostExecute(Boolean result) { - super.onPostExecute(result); - - if (result == null) { - Notify.create(getActivity(), - "Connection error while checking username!", Notify.Style.ERROR).show(); - return; - } - - if (!result) { - Notify.create(getActivity(), - "This handle does not exist on Github!", Notify.Style.ERROR).show(); - return; - } - - LinkedIdCreateGithubStep2Fragment frag = - LinkedIdCreateGithubStep2Fragment.newInstance(handle); - - mLinkedIdWizard.loadFragment(null, frag, LinkedIdWizard.FRAG_ACTION_TO_RIGHT); - } - }.execute(); - - } - }); - - view.findViewById(R.id.back_button).setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - mLinkedIdWizard.loadFragment(null, null, LinkedIdWizard.FRAG_ACTION_TO_LEFT); - } - }); - - mEditHandle = (EditText) view.findViewById(R.id.linked_create_github_handle); - - return view; - } - - /* not used at this point, too much hassle - private static Boolean checkHandle(String handle) { - try { - HttpURLConnection nection = - (HttpURLConnection) new URL("https://api.github.com/" + handle).openConnection(); - nection.setRequestMethod("HEAD"); - return nection.getResponseCode() == 200; - } catch (IOException e) { - e.printStackTrace(); - return null; - } - } - */ - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateGithubStep2Fragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateGithubStep2Fragment.java deleted file mode 100644 index a3a8c779f..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdCreateGithubStep2Fragment.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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.linked; - -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.linked.LinkedTokenResource; -import org.sufficientlysecure.keychain.linked.resources.GithubResource; - - -public class LinkedIdCreateGithubStep2Fragment extends LinkedIdCreateFinalFragment { - - public static final String ARG_HANDLE = "handle"; - - String mResourceHandle; - String mResourceString; - - public static LinkedIdCreateGithubStep2Fragment newInstance - (String handle) { - - LinkedIdCreateGithubStep2Fragment frag = new LinkedIdCreateGithubStep2Fragment(); - - Bundle args = new Bundle(); - args.putString(ARG_HANDLE, handle); - frag.setArguments(args); - - return frag; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mResourceString = - GithubResource.generate(getActivity(), mLinkedIdWizard.mFingerprint); - - mResourceHandle = getArguments().getString(ARG_HANDLE); - - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = super.onCreateView(inflater, container, savedInstanceState); - - if (view != null) { - - view.findViewById(R.id.button_send).setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - proofSend(); - } - }); - - view.findViewById(R.id.button_share).setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - proofShare(); - } - }); - - } - - return view; - } - - @Override - LinkedTokenResource getResource(OperationLog log) { - return GithubResource.searchInGithubStream(getActivity(), mResourceHandle, mResourceString, log); - } - - @Override - protected View newView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - return inflater.inflate(R.layout.linked_create_github_fragment_step2, container, false); - } - - private void proofShare() { - Intent sendIntent = new Intent(); - sendIntent.setAction(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_TEXT, mResourceString); - sendIntent.setType("text/plain"); - startActivity(sendIntent); - } - - private void proofSend() { - Uri.Builder builder = Uri.parse("https://gist.github.com/").buildUpon(); - builder.appendQueryParameter("text", mResourceString); - Uri uri = builder.build(); - - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - getActivity().startActivity(intent); - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdViewFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdViewFragment.java index 7007fa50c..5630932b4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdViewFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdViewFragment.java @@ -211,6 +211,8 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements null, State.INVALID, KeyFormattingUtils.DEFAULT_COLOR); break; } + } else { + mViewHolder.mLinkedIdHolder.vVerified.setImageResource(R.drawable.octo_link_24dp); } mViewHolder.mLinkedIdHolder.setData(mContext, mLinkedId); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdWizard.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdWizard.java index 3441bb399..8c677199d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdWizard.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/linked/LinkedIdWizard.java @@ -17,7 +17,6 @@ package org.sufficientlysecure.keychain.ui.linked; -import java.util.Random; import android.content.Context; import android.content.Intent; @@ -25,19 +24,20 @@ import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; +import android.support.v4.app.NavUtils; +import android.support.v4.app.TaskStackBuilder; +import android.view.MenuItem; import android.view.View; import android.view.inputmethod.InputMethodManager; -import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.base.BaseActivity; -import org.sufficientlysecure.keychain.ui.util.Notify; -import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.util.Log; public class LinkedIdWizard extends BaseActivity { @@ -131,53 +131,34 @@ public class LinkedIdWizard extends BaseActivity { inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0); } - private String mOAuthCode, mOAuthState; - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - - Uri uri = intent.getData(); - Log.d(Constants.TAG, "received oauth uri: " + uri); - if (mOAuthState != null && uri != null) { - String state = uri.getQueryParameter("state"); - if (!mOAuthState.equalsIgnoreCase(state)) { - Notify.create(this, "OAuth State Error!", Style.ERROR).show(); - return; - } - mOAuthCode = uri.getQueryParameter("code"); + public void onBackPressed() { + if (!getFragmentManager().popBackStackImmediate()) { + navigateBack(); } - } - public String oAuthGetCode() { - try { - return mOAuthCode; - } finally { - mOAuthCode = null; + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + // Respond to the action bar's Up/Home button + case android.R.id.home: + navigateBack(); + return true; } + return super.onOptionsItemSelected(item); } - public String oAuthGetState() { - return mOAuthState; - } - - public void oAuthRequest(String hostAndPath, String clientId, String scope) { - - byte[] buf = new byte[16]; - new Random().nextBytes(buf); - mOAuthState = new String(Hex.encode(buf)); - - Intent intent = new Intent( - Intent.ACTION_VIEW, - Uri.parse("https://" + hostAndPath + - "?client_id=" + clientId + - "&scope=" + scope + - "&redirect_uri=oauth-openkeychain://linked/" + - "&state=" + mOAuthState)); - - startActivity(intent); - + private void navigateBack() { + Intent upIntent = NavUtils.getParentActivityIntent(this); + upIntent.setData(KeyRings.buildGenericKeyRingUri(mMasterKeyId)); + // This activity is NOT part of this app's task, so create a new task + // when navigating up, with a synthesized back stack. + TaskStackBuilder.create(this) + // Add all of this activity's parents to the back stack + .addNextIntentWithParentStack(upIntent) + // Navigate up to the closest parent + .startActivities(); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java index e3ec3d34b..04ed35deb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java @@ -119,8 +119,7 @@ public abstract class KeySpinner extends AppCompatSpinner implements if (getContext() instanceof FragmentActivity) { ((FragmentActivity) getContext()).getSupportLoaderManager().restartLoader(LOADER_ID, null, this); } else { - throw new AssertionError("KeySpinner must be attached to FragmentActivity, this is " - + getContext().getClass()); + // ignore, this happens during preview! we use fragmentactivities everywhere either way } } |