aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/linked/resources/TwitterResource.java
diff options
context:
space:
mode:
authorVincent Breitmoser <valodim@mugenguild.com>2015-05-09 12:24:48 +0200
committerVincent Breitmoser <valodim@mugenguild.com>2015-05-09 12:24:48 +0200
commit4378f8f871f6a47321352f90a59cfaad7f52279b (patch)
tree1283eb8a92ce1eeea64ab09c21f13e644569ac91 /OpenKeychain/src/main/java/org/sufficientlysecure/keychain/linked/resources/TwitterResource.java
parent39382e978f554a8da0ee7698bd84cbb2023b186d (diff)
downloadopen-keychain-4378f8f871f6a47321352f90a59cfaad7f52279b.tar.gz
open-keychain-4378f8f871f6a47321352f90a59cfaad7f52279b.tar.bz2
open-keychain-4378f8f871f6a47321352f90a59cfaad7f52279b.zip
linked-ids: code cleanup, handle all lint errors
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/linked/resources/TwitterResource.java')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/linked/resources/TwitterResource.java244
1 files changed, 244 insertions, 0 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/linked/resources/TwitterResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/linked/resources/TwitterResource.java
new file mode 100644
index 000000000..c981e2bd6
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/linked/resources/TwitterResource.java
@@ -0,0 +1,244 @@
+package org.sufficientlysecure.keychain.linked.resources;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.StringRes;
+import android.util.Log;
+
+import com.textuality.keybase.lib.JWalk;
+
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
+import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
+import org.sufficientlysecure.keychain.linked.LinkedCookieResource;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class TwitterResource extends LinkedCookieResource {
+
+ final String mHandle;
+ final String mTweetId;
+
+ TwitterResource(Set<String> flags, HashMap<String,String> params,
+ URI uri, String handle, String tweetId) {
+ super(flags, params, uri);
+
+ mHandle = handle;
+ mTweetId = tweetId;
+ }
+
+ public static TwitterResource create(URI uri) {
+ return create(new HashSet<String>(), new HashMap<String,String>(), uri);
+ }
+
+ public static TwitterResource create(Set<String> flags, HashMap<String,String> params, URI uri) {
+
+ // no params or flags
+ if (!flags.isEmpty() || !params.isEmpty()) {
+ return null;
+ }
+
+ Pattern p = Pattern.compile("https://twitter\\.com/([a-zA-Z0-9_]+)/status/([0-9]+)");
+ Matcher match = p.matcher(uri.toString());
+ if (!match.matches()) {
+ return null;
+ }
+ String handle = match.group(1);
+ String tweetId = match.group(2);
+
+ return new TwitterResource(flags, params, uri, handle, tweetId);
+
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ protected String fetchResource(OperationLog log, int indent) throws IOException, HttpStatusException,
+ JSONException {
+
+ String authToken;
+ try {
+ authToken = getAuthToken();
+ } catch (IOException | HttpStatusException | JSONException e) {
+ log.add(LogType.MSG_LV_ERROR_TWITTER_AUTH, indent);
+ return null;
+ }
+
+ HttpGet httpGet =
+ new HttpGet("https://api.twitter.com/1.1/statuses/show.json"
+ + "?id=" + mTweetId
+ + "&include_entities=false");
+
+ // construct a normal HTTPS request and include an Authorization
+ // header with the value of Bearer <>
+ httpGet.setHeader("Authorization", "Bearer " + authToken);
+ httpGet.setHeader("Content-Type", "application/json");
+
+ try {
+ String response = getResponseBody(httpGet);
+ JSONObject obj = new JSONObject(response);
+ JSONObject user = obj.getJSONObject("user");
+ if (!mHandle.equalsIgnoreCase(user.getString("screen_name"))) {
+ log.add(LogType.MSG_LV_ERROR_TWITTER_HANDLE, indent);
+ return null;
+ }
+
+ // update the results with the body of the response
+ return obj.getString("text");
+ } catch (JSONException e) {
+ log.add(LogType.MSG_LV_ERROR_TWITTER_RESPONSE, indent);
+ return null;
+ }
+
+ }
+
+ @Override
+ public @DrawableRes int getDisplayIcon() {
+ return R.drawable.linked_twitter;
+ }
+
+ @Override
+ public @StringRes
+ int getVerifiedText(boolean isSecret) {
+ return isSecret ? R.string.linked_verified_secret_twitter : R.string.linked_verified_twitter;
+ }
+
+ @Override
+ public String getDisplayTitle(Context context) {
+ return context.getString(R.string.linked_title_twitter);
+ }
+
+ @Override
+ public String getDisplayComment(Context context) {
+ return "@" + mHandle;
+ }
+
+ @Override
+ public boolean isViewable() {
+ return true;
+ }
+
+ @Override
+ public Intent getViewIntent() {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(mSubUri.toString()));
+ return intent;
+ }
+
+ @SuppressWarnings("deprecation")
+ public static TwitterResource searchInTwitterStream(
+ String screenName, String needle, OperationLog log) {
+
+ String authToken;
+ try {
+ authToken = getAuthToken();
+ } catch (IOException | HttpStatusException | JSONException e) {
+ log.add(LogType.MSG_LV_ERROR_TWITTER_AUTH, 1);
+ return null;
+ }
+
+ HttpGet httpGet =
+ new HttpGet("https://api.twitter.com/1.1/statuses/user_timeline.json"
+ + "?screen_name=" + screenName
+ + "&count=15"
+ + "&include_rts=false"
+ + "&trim_user=true"
+ + "&exclude_replies=true");
+
+ // construct a normal HTTPS request and include an Authorization
+ // header with the value of Bearer <>
+ httpGet.setHeader("Authorization", "Bearer " + authToken);
+ httpGet.setHeader("Content-Type", "application/json");
+
+ try {
+ String response = getResponseBody(httpGet);
+ JSONArray array = new JSONArray(response);
+
+ for (int i = 0; i < array.length(); i++) {
+ JSONObject obj = array.getJSONObject(i);
+ String tweet = obj.getString("text");
+ if (tweet.contains(needle)) {
+ String id = obj.getString("id_str");
+ URI uri = URI.create("https://twitter.com/" + screenName + "/status/" + id);
+ return create(uri);
+ }
+ }
+
+ // update the results with the body of the response
+ log.add(LogType.MSG_LV_FETCH_ERROR_NOTHING, 1);
+ return null;
+
+ } catch (HttpStatusException e) {
+ // log verbose output to logcat
+ Log.e(Constants.TAG, "http error (" + e.getStatus() + "): " + e.getReason());
+ log.add(LogType.MSG_LV_FETCH_ERROR, 1, Integer.toString(e.getStatus()));
+ } catch (MalformedURLException e) {
+ log.add(LogType.MSG_LV_FETCH_ERROR_URL, 1);
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "io error", e);
+ log.add(LogType.MSG_LV_FETCH_ERROR_IO, 1);
+ } catch (JSONException e) {
+ Log.e(Constants.TAG, "json error", e);
+ log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, 1);
+ }
+
+ return null;
+ }
+
+ private static String cachedAuthToken;
+
+ @SuppressWarnings("deprecation")
+ private static String getAuthToken() throws IOException, HttpStatusException, JSONException {
+ if (cachedAuthToken != null) {
+ return cachedAuthToken;
+ }
+ String base64Encoded = rot13("D293FQqanH0jH29KIaWJER5DomqSGRE2Ewc1LJACn3cbD1c"
+ + "Fq1bmqSAQAz5MI2cIHKOuo3cPoRAQI1OyqmIVFJS6LHMXq2g6MRLkIj") + "==";
+
+ // Step 2: Obtain a bearer token
+ HttpPost httpPost = new HttpPost("https://api.twitter.com/oauth2/token");
+ httpPost.setHeader("Authorization", "Basic " + base64Encoded);
+ httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
+ httpPost.setEntity(new StringEntity("grant_type=client_credentials"));
+ JSONObject rawAuthorization = new JSONObject(getResponseBody(httpPost));
+
+ // Applications should verify that the value associated with the
+ // token_type key of the returned object is bearer
+ if (!"bearer".equals(JWalk.getString(rawAuthorization, "token_type"))) {
+ throw new JSONException("Expected bearer token in response!");
+ }
+
+ cachedAuthToken = rawAuthorization.getString("access_token");
+ return cachedAuthToken;
+
+ }
+
+ public static String rot13(String input) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < input.length(); i++) {
+ char c = input.charAt(i);
+ if (c >= 'a' && c <= 'm') c += 13;
+ else if (c >= 'A' && c <= 'M') c += 13;
+ else if (c >= 'n' && c <= 'z') c -= 13;
+ else if (c >= 'N' && c <= 'Z') c -= 13;
+ sb.append(c);
+ }
+ return sb.toString();
+ }
+
+}