diff options
Diffstat (limited to 'OpenKeychain/src/main')
6 files changed, 224 insertions, 46 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index fba52c4ad..7cb5e4904 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -777,6 +777,7 @@ public abstract class OperationResult implements Parcelable { MSG_LV_FETCH_ERROR (LogLevel.ERROR, R.string.msg_lv_fetch_error), MSG_LV_FETCH_ERROR_URL (LogLevel.ERROR, R.string.msg_lv_fetch_error_url), MSG_LV_FETCH_ERROR_IO (LogLevel.ERROR, R.string.msg_lv_fetch_error_io), + MSG_LV_FETCH_ERROR_FORMAT(LogLevel.ERROR, R.string.msg_lv_fetch_error_format), //export log MSG_EXPORT_LOG(LogLevel.START,R.string.msg_export_log_start), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java index 21a8c8f98..2b9156417 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java @@ -2,6 +2,12 @@ package org.sufficientlysecure.keychain.pgp.linked; import android.content.Context; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.params.BasicHttpParams; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; @@ -9,6 +15,10 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.Operat import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.net.URI; import java.util.HashMap; import java.util.Map.Entry; @@ -117,4 +127,49 @@ public abstract class LinkedCookieResource extends LinkedResource { } + public static String getResponseBody(HttpRequestBase request) throws IOException, HttpStatusException { + StringBuilder sb = new StringBuilder(); + + DefaultHttpClient httpClient = new DefaultHttpClient(new BasicHttpParams()); + HttpResponse response = httpClient.execute(request); + int statusCode = response.getStatusLine().getStatusCode(); + String reason = response.getStatusLine().getReasonPhrase(); + + if (statusCode != 200) { + throw new HttpStatusException(statusCode, reason); + } + + HttpEntity entity = response.getEntity(); + InputStream inputStream = entity.getContent(); + + BufferedReader bReader = new BufferedReader( + new InputStreamReader(inputStream, "UTF-8"), 8); + String line; + while ((line = bReader.readLine()) != null) { + sb.append(line); + } + + return sb.toString(); + } + + public static class HttpStatusException extends Throwable { + + private final int mStatusCode; + private final String mReason; + + HttpStatusException(int statusCode, String reason) { + mStatusCode = statusCode; + mReason = reason; + } + + public int getStatus() { + return mStatusCode; + } + + public String getReason() { + return mReason; + } + + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java new file mode 100644 index 000000000..de313e14e --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java @@ -0,0 +1,146 @@ +package org.sufficientlysecure.keychain.pgp.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 org.apache.http.client.methods.HttpGet; +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.pgp.linked.LinkedCookieResource; +import org.sufficientlysecure.keychain.util.Log; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URI; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +public class GithubResource extends LinkedCookieResource { + + final String mHandle; + final String mGistId; + + GithubResource(Set<String> flags, HashMap<String,String> params, URI uri, + String handle, String gistId) { + super(flags, params, uri); + + mHandle = handle; + mGistId = gistId; + } + + public static String generateText (Context context, byte[] fingerprint) { + String cookie = LinkedCookieResource.generate(context, fingerprint); + + return String.format(context.getResources().getString(R.string.linked_id_github_text), cookie); + } + + @Override + protected String fetchResource (OperationLog log, int indent) { + + log.add(LogType.MSG_LV_FETCH, indent, mSubUri.toString()); + indent += 1; + + try { + + HttpGet httpGet = new HttpGet("https://api.github.com/gists/" + mGistId); + + String response = getResponseBody(httpGet); + + JSONObject obj = new JSONObject(response); + + JSONObject owner = obj.getJSONObject("owner"); + if (!mHandle.equals(owner.getString("login"))) { + log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, indent); + return null; + } + + JSONObject files = obj.getJSONObject("files"); + Iterator<String> it = files.keys(); + if (it.hasNext()) { + // TODO can there be multiple candidates? + JSONObject file = files.getJSONObject(it.next()); + return file.getString("content"); + } + + } 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, indent, Integer.toString(e.getStatus())); + } catch (MalformedURLException e) { + log.add(LogType.MSG_LV_FETCH_ERROR_URL, indent); + } catch (IOException e) { + Log.e(Constants.TAG, "io error", e); + log.add(LogType.MSG_LV_FETCH_ERROR_IO, indent); + } catch (JSONException e) { + Log.e(Constants.TAG, "json error", e); + log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, indent); + } + return null; + + } + + public static GithubResource 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://gist\\.github\\.com/([a-zA-Z0-9_]+)/([0-9a-f]+)"); + Matcher match = p.matcher(uri.toString()); + if (!match.matches()) { + return null; + } + String handle = match.group(1); + String gistId = match.group(2); + + return new GithubResource(flags, params, uri, handle, gistId); + + } + + + @Override + public @DrawableRes + int getDisplayIcon() { + return R.drawable.github; + } + + @Override + public @StringRes + int getVerifiedText() { + return R.string.linked_verified_github; + } + + @Override + public String getDisplayTitle(Context context) { + return "Github"; + } + + @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; + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java index 8bc872f51..136d87d03 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java @@ -9,27 +9,19 @@ import android.util.Log; import com.textuality.keybase.lib.JWalk; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.params.BasicHttpParams; 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.pgp.linked.LinkedCookieResource; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; import java.net.URI; import java.util.HashMap; import java.util.HashSet; @@ -61,7 +53,7 @@ public class TwitterResource extends LinkedCookieResource { return null; } - Pattern p = Pattern.compile("https://twitter.com/([a-zA-Z0-9_]+)/status/([0-9]+)"); + 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; @@ -102,16 +94,25 @@ public class TwitterResource extends LinkedCookieResource { JSONObject user = obj.getJSONObject("user"); if (!mHandle.equalsIgnoreCase(user.getString("screen_name"))) { + log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, indent); return null; } // update the results with the body of the response return obj.getString("text"); + } 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, indent, Integer.toString(e.getStatus())); + } catch (IOException e) { + Log.e(Constants.TAG, "io error", e); + log.add(LogType.MSG_LV_FETCH_ERROR_IO, indent); } catch (JSONException e) { - Log.e(Constants.TAG, "json error parsing stream", e); - return null; + Log.e(Constants.TAG, "json error", e); + log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, indent); } + return null; } @Override @@ -184,10 +185,11 @@ public class TwitterResource extends LinkedCookieResource { // update the results with the body of the response return null; - } catch (JSONException e) { - Log.e(Constants.TAG, "json error parsing stream", e); - return null; + } catch (JSONException | HttpStatusException | IOException e) { + Log.e(Constants.TAG, "exception parsing stream", e); } + + return null; } private static String authToken; @@ -217,42 +219,13 @@ public class TwitterResource extends LinkedCookieResource { authToken = JWalk.getString(rawAuthorization, "access_token"); return authToken; - } catch (UnsupportedEncodingException | JSONException | IllegalStateException ex) { - Log.e(Constants.TAG, "auth token fetching error", ex); + } catch (JSONException | IllegalStateException | HttpStatusException | IOException ex) { + Log.e(Constants.TAG, "exception fetching auth token", ex); return null; } } - private static String getResponseBody(HttpRequestBase request) { - StringBuilder sb = new StringBuilder(); - try { - - DefaultHttpClient httpClient = new DefaultHttpClient(new BasicHttpParams()); - HttpResponse response = httpClient.execute(request); - int statusCode = response.getStatusLine().getStatusCode(); - String reason = response.getStatusLine().getReasonPhrase(); - - if (statusCode == 200) { - - HttpEntity entity = response.getEntity(); - InputStream inputStream = entity.getContent(); - - BufferedReader bReader = new BufferedReader( - new InputStreamReader(inputStream, "UTF-8"), 8); - String line; - while ((line = bReader.readLine()) != null) { - sb.append(line); - } - } else { - sb.append(reason); - } - } catch (IOException e) { - Log.e(Constants.TAG, "http request error", e); - } - return sb.toString(); - } - public static String rot13(String input) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < input.length(); i++) { diff --git a/OpenKeychain/src/main/res/drawable/github.png b/OpenKeychain/src/main/res/drawable/github.png Binary files differnew file mode 100644 index 000000000..8b25551a9 --- /dev/null +++ b/OpenKeychain/src/main/res/drawable/github.png diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 4902485b0..d353422d3 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -1178,6 +1178,7 @@ <string name="msg_lv_fetch_error">"Server error (HTTP %s)"</string> <string name="msg_lv_fetch_error_url">"URL is malformed!"</string> <string name="msg_lv_fetch_error_io">"IO Error!"</string> + <string name="msg_lv_fetch_error_format">"Format error!"</string> <string name="msg_acc_saved">"Account saved"</string> @@ -1307,6 +1308,7 @@ <string name="linked_create_verify">"Verify"</string> <string name="linked_text_clipboard">Text has been copied to clipboard</string> <string name="linked_verified_https">"The Website has been fetched and verified."</string> + <string name="linked_verified_github">"The Gist has been fetched and verified."</string> <string name="linked_verified_dns">"The DNS record has been fetched and verified."</string> <string name="linked_verified_twitter">"The Tweet has been fetched and verified."</string> <plurals name="linked_id_expand"> @@ -1317,6 +1319,7 @@ <string name="linked_select_1">"A \'linked identity\' connects your pgp key to a resource on the web."</string> <string name="linked_select_2">"Please select a type:"</string> <string name="linked_id_generic_text">"This file claims ownership of the OpenPGP key with long id %2$s.\n\nCookie for proof:\n%1$s"</string> + <string name="linked_id_github_text">"This Gist confirms the Linked Identity in my OpenPGP key, and links it to this Github account.\n\nCookie for proof:\n%1$s"</string> <string name="linked_verifying">"Verifying…"</string> <string name="linked_verify_success">"Verified!"</string> <string name="linked_verify_error">"Verification error!"</string> |