some work on twitter resource

This commit is contained in:
Vincent Breitmoser
2015-01-13 00:09:48 +01:00
parent d51621538a
commit e71d620840
12 changed files with 1307 additions and 25 deletions

View File

@@ -1,7 +1,7 @@
package org.sufficientlysecure.keychain.pgp.affirmation.resources;
import android.content.Context;
import android.util.Base64;
import android.util.JsonReader;
import com.textuality.keybase.lib.JWalk;
@@ -35,6 +35,11 @@ public class TwitterResource extends AffirmationResource {
super(flags, params, uri);
}
public static String generateText (Context context, byte[] fingerprint, String nonce) {
// nothing special here for now, might change this later
return AffirmationResource.generate(context, fingerprint, nonce);
}
private String getTwitterStream(String screenName) {
String results = null;

View File

@@ -0,0 +1,125 @@
/*
* 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.affirmations;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Patterns;
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.pgp.affirmation.LinkedIdentity;
import org.sufficientlysecure.keychain.pgp.affirmation.resources.GenericHttpsResource;
public class AffirmationCreateDnsStep1Fragment extends Fragment {
AffirmationWizard mAffirmationWizard;
EditText mEditUri;
/**
* Creates new instance of this fragment
*/
public static AffirmationCreateDnsStep1Fragment newInstance() {
AffirmationCreateDnsStep1Fragment frag = new AffirmationCreateDnsStep1Fragment();
Bundle args = new Bundle();
frag.setArguments(args);
return frag;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mAffirmationWizard = (AffirmationWizard) getActivity();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.affirmation_create_dns_fragment_step1, container, false);
view.findViewById(R.id.next_button).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
String uri = "https://" + mEditUri.getText();
if (!checkUri(uri)) {
return;
}
String proofNonce = LinkedIdentity.generateNonce();
String proofText = GenericHttpsResource.generateText(getActivity(),
mAffirmationWizard.mFingerprint, proofNonce);
AffirmationCreateHttpsStep2Fragment frag =
AffirmationCreateHttpsStep2Fragment.newInstance(uri, proofNonce, proofText);
mAffirmationWizard.loadFragment(null, frag, AffirmationWizard.FRAG_ACTION_TO_RIGHT);
}
});
mEditUri = (EditText) view.findViewById(R.id.affirmation_create_https_uri);
mEditUri.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
@Override
public void afterTextChanged(Editable editable) {
String uri = "https://" + editable;
if (uri.length() > 0) {
if (checkUri(uri)) {
mEditUri.setCompoundDrawablesWithIntrinsicBounds(0, 0,
R.drawable.uid_mail_ok, 0);
} else {
mEditUri.setCompoundDrawablesWithIntrinsicBounds(0, 0,
R.drawable.uid_mail_bad, 0);
}
} else {
// remove drawable if email is empty
mEditUri.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
}
}
});
mEditUri.setText("mugenguild.com/pgpkey.txt");
return view;
}
private static boolean checkUri(String uri) {
return Patterns.WEB_URL.matcher(uri).matches();
}
}

View File

@@ -0,0 +1,132 @@
/*
* 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.affirmations;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Patterns;
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.pgp.affirmation.LinkedIdentity;
import org.sufficientlysecure.keychain.pgp.affirmation.resources.GenericHttpsResource;
import org.sufficientlysecure.keychain.pgp.affirmation.resources.TwitterResource;
import org.sufficientlysecure.keychain.ui.util.Notify;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
public class AffirmationCreateTwitterStep1Fragment extends Fragment {
AffirmationWizard mAffirmationWizard;
EditText mEditHandle;
/**
* Creates new instance of this fragment
*/
public static AffirmationCreateTwitterStep1Fragment newInstance() {
AffirmationCreateTwitterStep1Fragment frag = new AffirmationCreateTwitterStep1Fragment();
Bundle args = new Bundle();
frag.setArguments(args);
return frag;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mAffirmationWizard = (AffirmationWizard) getActivity();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.affirmation_create_twitter_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; // checkHandle(handle);
}
@Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
if (result == null) {
Notify.showNotify(getActivity(), "Connection error while checking username!", Notify.Style.ERROR);
return;
}
if (!result) {
Notify.showNotify(getActivity(), "This handle does not exist on Twitter!", Notify.Style.ERROR);
return;
}
String proofNonce = LinkedIdentity.generateNonce();
String proofText = TwitterResource.generateText(getActivity(),
mAffirmationWizard.mFingerprint, proofNonce);
AffirmationCreateTwitterStep2Fragment frag =
AffirmationCreateTwitterStep2Fragment.newInstance(handle, proofNonce, proofText);
mAffirmationWizard.loadFragment(null, frag, AffirmationWizard.FRAG_ACTION_TO_RIGHT);
}
}.execute();
}
});
mEditHandle = (EditText) view.findViewById(R.id.linked_create_twitter_handle);
mEditHandle.setText("Valodim");
return view;
}
private static Boolean checkHandle(String handle) {
try {
HttpURLConnection nection =
(HttpURLConnection) new URL("https://twitter.com/" + handle).openConnection();
nection.setRequestMethod("HEAD");
return nection.getResponseCode() == 200;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}

View File

@@ -0,0 +1,142 @@
/*
* 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.affirmations;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.InputFilter;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
public class AffirmationCreateTwitterStep2Fragment extends Fragment {
private static final int REQUEST_CODE_OUTPUT = 0x00007007;
public static final String HANDLE = "uri", NONCE = "nonce", TEXT = "text";
AffirmationWizard mAffirmationWizard;
EditText mEditTweetCustom, mEditTweetPreview;
ImageView mVerifyImage;
View mVerifyProgress;
TextView mVerifyStatus, mEditTweetTextLen;
String mResourceHandle;
String mResourceNonce, mResourceString;
/**
* Creates new instance of this fragment
*/
public static AffirmationCreateTwitterStep2Fragment newInstance
(String handle, String proofNonce, String proofText) {
AffirmationCreateTwitterStep2Fragment frag = new AffirmationCreateTwitterStep2Fragment();
Bundle args = new Bundle();
args.putString(HANDLE, handle);
args.putString(NONCE, proofNonce);
args.putString(TEXT, proofText);
frag.setArguments(args);
return frag;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.affirmation_create_twitter_fragment_step2, container, false);
mResourceHandle = getArguments().getString(HANDLE);
mResourceNonce = getArguments().getString(NONCE);
mResourceString = getArguments().getString(TEXT);
view.findViewById(R.id.next_button).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
AffirmationCreateTwitterStep3Fragment frag =
AffirmationCreateTwitterStep3Fragment.newInstance(mResourceHandle,
mResourceNonce, mResourceString,
mEditTweetCustom.getText().toString());
mAffirmationWizard.loadFragment(null, frag, AffirmationWizard.FRAG_ACTION_TO_RIGHT);
}
});
mVerifyImage = (ImageView) view.findViewById(R.id.verify_image);
mVerifyProgress = view.findViewById(R.id.verify_progress);
mVerifyStatus = (TextView) view.findViewById(R.id.verify_status);
mEditTweetPreview = (EditText) view.findViewById(R.id.linked_create_twitter_preview);
mEditTweetPreview.setText(mResourceString);
mEditTweetCustom = (EditText) view.findViewById(R.id.linked_create_twitter_custom);
mEditTweetCustom.setFilters(new InputFilter[] {
new InputFilter.LengthFilter(139 - mResourceString.length())
});
mEditTweetTextLen = (TextView) view.findViewById(R.id.linked_create_twitter_textlen);
mEditTweetTextLen.setText(mResourceString.length() + "/140");
mEditTweetCustom.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
@Override
public void afterTextChanged(Editable editable) {
if (editable != null && editable.length() > 0) {
String str = editable + " " + mResourceString;
mEditTweetPreview.setText(str);
mEditTweetTextLen.setText(str.length() + "/140");
mEditTweetTextLen.setTextColor(getResources().getColor(str.length() == 140
? R.color.android_red_dark
: R.color.primary_dark_material_light));
} else {
mEditTweetPreview.setText(mResourceString);
mEditTweetTextLen.setText(mResourceString.length() + "/140");
}
}
});
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mAffirmationWizard = (AffirmationWizard) getActivity();
}
}

View File

@@ -0,0 +1,243 @@
/*
* 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.affirmations;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.PorterDuff;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
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 android.widget.ImageView;
import android.widget.TextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult;
import org.sufficientlysecure.keychain.pgp.affirmation.resources.GenericHttpsResource;
import org.sufficientlysecure.keychain.pgp.affirmation.resources.TwitterResource;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
import org.sufficientlysecure.keychain.util.FileHelper;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
public class AffirmationCreateTwitterStep3Fragment extends Fragment {
public static final String HANDLE = "uri", NONCE = "nonce", TEXT = "text", CUSTOM = "custom";
AffirmationWizard mAffirmationWizard;
EditText mEditTweetPreview;
ImageView mVerifyImage;
View mVerifyProgress;
TextView mVerifyStatus;
String mResourceHandle, mCustom, mFullString;
String mResourceNonce, mResourceString;
/**
* Creates new instance of this fragment
*/
public static AffirmationCreateTwitterStep3Fragment newInstance
(String handle, String proofNonce, String proofText, String customText) {
AffirmationCreateTwitterStep3Fragment frag = new AffirmationCreateTwitterStep3Fragment();
Bundle args = new Bundle();
args.putString(HANDLE, handle);
args.putString(NONCE, proofNonce);
args.putString(TEXT, proofText);
args.putString(CUSTOM, customText);
frag.setArguments(args);
return frag;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.affirmation_create_twitter_fragment_step3, container, false);
mResourceHandle = getArguments().getString(HANDLE);
mResourceNonce = getArguments().getString(NONCE);
mResourceString = getArguments().getString(TEXT);
mCustom = getArguments().getString(CUSTOM);
mFullString = mCustom.isEmpty() ? mResourceString : (mCustom + " " + mResourceString);
mVerifyImage = (ImageView) view.findViewById(R.id.verify_image);
mVerifyProgress = view.findViewById(R.id.verify_progress);
mVerifyStatus = (TextView) view.findViewById(R.id.verify_status);
mEditTweetPreview = (EditText) view.findViewById(R.id.linked_create_twitter_preview);
mEditTweetPreview.setText(mFullString);
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();
}
});
view.findViewById(R.id.button_verify).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
proofVerify();
}
});
setVerifyProgress(false, null);
mVerifyStatus.setText(R.string.linked_verify_pending);
view.findViewById(R.id.next_button).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// AffirmationCreateHttpsStep2Fragment frag =
// AffirmationCreateHttpsStep2Fragment.newInstance();
// mAffirmationWizard.loadFragment(null, frag, AffirmationWizard.FRAG_ACTION_TO_RIGHT);
}
});
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mAffirmationWizard = (AffirmationWizard) getActivity();
}
public void setVerifyProgress(boolean on, Boolean success) {
mVerifyProgress.setVisibility(on ? View.VISIBLE : View.GONE);
mVerifyImage.setVisibility(on ? View.GONE : View.VISIBLE);
if (success == null) {
mVerifyStatus.setText(R.string.linked_verifying);
mVerifyImage.setImageResource(R.drawable.status_signature_unverified_cutout);
mVerifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light),
PorterDuff.Mode.SRC_IN);
} else if (success) {
mVerifyStatus.setText(R.string.linked_verify_success);
mVerifyImage.setImageResource(R.drawable.status_signature_verified_cutout);
mVerifyImage.setColorFilter(getResources().getColor(R.color.android_green_dark),
PorterDuff.Mode.SRC_IN);
} else {
mVerifyStatus.setText(R.string.linked_verify_error);
mVerifyImage.setImageResource(R.drawable.status_signature_unknown_cutout);
mVerifyImage.setColorFilter(getResources().getColor(R.color.android_red_dark),
PorterDuff.Mode.SRC_IN);
}
}
public void proofVerify() {
setVerifyProgress(true, null);
/*
try {
final TwitterResource resource = TwitterResource.createNew(new URI(mResourceHandle));
new AsyncTask<Void,Void,LinkedVerifyResult>() {
@Override
protected LinkedVerifyResult doInBackground(Void... params) {
return resource.verify(mAffirmationWizard.mFingerprint, mResourceNonce);
}
@Override
protected void onPostExecute(LinkedVerifyResult result) {
super.onPostExecute(result);
if (result.success()) {
setVerifyProgress(false, true);
} else {
setVerifyProgress(false, false);
// on error, show error message
result.createNotify(getActivity()).show();
}
}
}.execute();
} catch (URISyntaxException e) {
e.printStackTrace();
}
*/
}
private void proofShare() {
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, mFullString);
sendIntent.setType("text/plain");
startActivity(sendIntent);
}
private void proofSend() {
Intent tweetIntent = new Intent(Intent.ACTION_SEND);
tweetIntent.putExtra(Intent.EXTRA_TEXT, mFullString);
tweetIntent.setType("text/plain");
PackageManager packManager = getActivity().getPackageManager();
List<ResolveInfo> resolvedInfoList = packManager.queryIntentActivities(tweetIntent,
PackageManager.MATCH_DEFAULT_ONLY);
boolean resolved = false;
for(ResolveInfo resolveInfo : resolvedInfoList){
if(resolveInfo.activityInfo.packageName.startsWith("com.twitter.android")) {
tweetIntent.setClassName(
resolveInfo.activityInfo.packageName,
resolveInfo.activityInfo.name );
resolved = true;
break;
}
}
if (resolved) {
startActivity(tweetIntent);
} else {
Notify.showNotify(getActivity(),
"Twitter app is not installed, please use the send intent!",
Notify.Style.ERROR);
}
}
}

View File

@@ -56,6 +56,28 @@ public class AffirmationSelectFragment extends Fragment {
}
});
view.findViewById(R.id.affirmation_create_dns_button)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AffirmationCreateDnsStep1Fragment frag =
AffirmationCreateDnsStep1Fragment.newInstance();
mAffirmationWizard.loadFragment(null, frag, AffirmationWizard.FRAG_ACTION_TO_RIGHT);
}
});
view.findViewById(R.id.affirmation_create_twitter_button)
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
AffirmationCreateTwitterStep1Fragment frag =
AffirmationCreateTwitterStep1Fragment.newInstance();
mAffirmationWizard.loadFragment(null, frag, AffirmationWizard.FRAG_ACTION_TO_RIGHT);
}
});
return view;
}