From c952e0ac80cc44f819f860021724f69195dafa43 Mon Sep 17 00:00:00 2001 From: gliechtenstein Date: Sun, 26 Nov 2017 20:52:59 -0800 Subject: [PATCH 01/10] Initial commit --- app/build.gradle | 1 + .../jasonette/seed/Action/JasonKeyAction.java | 427 ++++++++++++++++++ 2 files changed, 428 insertions(+) create mode 100644 app/src/main/java/com/jasonette/seed/Action/JasonKeyAction.java diff --git a/app/build.gradle b/app/build.gradle index 56b68ec5..38817ac9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -47,4 +47,5 @@ dependencies { compile 'com.github.florent37:singledateandtimepicker:1.0.8' compile 'com.jakewharton.timber:timber:4.5.1' compile 'com.google.android.gms:play-services:+' + compile 'com.scottyab:secure-preferences-lib:0.1.4' } diff --git a/app/src/main/java/com/jasonette/seed/Action/JasonKeyAction.java b/app/src/main/java/com/jasonette/seed/Action/JasonKeyAction.java new file mode 100644 index 00000000..42e40aa8 --- /dev/null +++ b/app/src/main/java/com/jasonette/seed/Action/JasonKeyAction.java @@ -0,0 +1,427 @@ +package com.jasonette.seed.Action; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Log; + +import com.jasonette.seed.Core.JasonViewActivity; +import com.jasonette.seed.Helper.JasonHelper; +import com.securepreferences.SecurePreferences; + +import org.json.JSONArray; +import org.json.JSONObject; + +public class JasonKeyAction { + SharedPreferences keys; + + public JSONObject _parse(final JSONObject action, Context context) { + JSONObject res = new JSONObject(); + try { + if (action.has("options")) { + JSONObject options = action.getJSONObject("options"); + if (options.has("url")) { + res.put("url", options.getString("url")); + res.put("remote", true); + } else { + res.put("url", ((JasonViewActivity)context).url); + res.put("remote", false); + } + } else { + res.put("url", ((JasonViewActivity)context).url); + res.put("remote", false); + } + } catch (Exception e) { + Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString()); + } + return res; + } + private void _fetch(JSONObject action, JSONObject event, JSONObject parsed, Context context) { + + keys = new SecurePreferences(context); + + try { + String serialized = keys.getString(parsed.getString("url"), "{}"); + JSONObject deserialized = new JSONObject(serialized); + /* + + deserialized := { + "items": [{ + ... + }, { + ... + }, { + ... + }] + } + + */ + + Boolean isRemote = parsed.getBoolean("remote"); + JSONArray items; + if (!deserialized.has("items")) { + items = new JSONArray(); + } else { + items = deserialized.getJSONArray("items"); + if (isRemote) { + // Need to filter only the public attributes + JSONArray filtered_items = new JSONArray(); + for (int i = 0; i < items.length(); i++) { + JSONObject item = items.getJSONObject(i); + JSONArray components = item.getJSONArray("components"); + JSONArray filtered_components = new JSONArray(); + for (int j = 0; j < components.length(); j++) { + JSONObject component = components.getJSONObject(j); + if (component.has("read")) { + if (component.getString("read").equalsIgnoreCase("public")) { + // "read": "public" component + // Add to filtered_components + filtered_components.put(component); + } + } + } + + JSONObject filtered_item = new JSONObject(); + filtered_item.put("components", filtered_components); + + filtered_items.put(filtered_item); + } + + items = filtered_items; + + + } else { + // Return the full object + // so don't do anything + } + } + + JSONObject res = new JSONObject(); + res.put("items", items); + + JasonHelper.next("success", action, res, event, context); + + // Filter only the "read + } catch (Exception e) { + Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString()); + } + + } + + + /** + + 1. Local Request + + { + "type": "$key.request" + } + + 2. Remote Request + + { + "type": "$key.request", + "options": { + "url": "file://wallet.json" + } + } + + **/ + public void request(final JSONObject action, final JSONObject data, final JSONObject event, final Context context) { + JSONObject parsed = _parse(action, context); + try { + Boolean isRemote = parsed.getBoolean("remote"); + if (isRemote) { + // remote. + // fetch only the public attributes. + _fetch(action, event, parsed, context); + } else { + // local + // fetch full key items + _fetch(action, event, parsed, context); + } + } catch (Exception e) { + Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString()); + } + + } + + /******************* + { + "type": "$key.add", + "options": { + "components": [{ + "key": "type", + "val": "ETH" + }, { + "key": "publickey", + "val": "0xjdnfenfkdewfhk384b4" + }, { + "key": "name", + "val": "Ethereum" + }, { + "key": "privatekey", + "val": "0x8dbgjenb8fngjwev742gfh47gh8ds87fh3bv" + }] + } + } + *******************/ + public void add(final JSONObject action, final JSONObject data, final JSONObject event, final Context context) { + JSONObject parsed = _parse(action, context); + try { + Boolean isRemote = parsed.getBoolean("remote"); + String url = parsed.getString("url"); + + if (!action.has("options")) { + JSONObject error = new JSONObject(); + error.put("message", "Must specify an item to add"); + JasonHelper.next("error", action, error, event, context); + return; + } + + if (!action.getJSONObject("options").has("components")) { + JSONObject error = new JSONObject(); + error.put("message", "A key item must have at least one component"); + JasonHelper.next("error", action, error, event, context); + return; + } + + if (isRemote) { + // remote. + // cannot add from remote + // 1. Construct error + JSONObject error = new JSONObject(); + error.put("message", "You are not allowed to add keys remotely"); + // 2. Trigger error callback + JasonHelper.next("error", action, error, event, context); + } else { + // local + keys = new SecurePreferences(context); + + try { + // Get {"items": [...]} from preferences + JSONArray items = _deserialize(url); + + // Add options object to the "items" array + JSONObject options = action.getJSONObject("options"); + items.put(options); + + JSONObject res = _serialize(url, items); + + // Return the updated {"items": [...]} as a return value + JasonHelper.next("success", action, res, event, context); + + } catch (Exception e) { + Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString()); + } + } + } catch (Exception e) { + Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString()); + } + + } + + + private JSONObject _serialize(String url, JSONArray items) { + try { + // update the {"items": [...]} with the new "items" array + JSONObject res = new JSONObject(); + res.put("items", items); + + // Update preference with the items + SharedPreferences.Editor editor = keys.edit(); + editor.putString(url, res.toString()); + editor.commit(); + return res; + + } catch (Exception e) { + Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString()); + return new JSONObject(); + } + } + private JSONArray _deserialize(String url) { + try { + String serialized = keys.getString(url, "{}"); + JSONObject deserialized = new JSONObject(serialized); + if (deserialized.has("items")) { + JSONArray items = deserialized.getJSONArray("items"); + return items; + } else { + return new JSONArray(); + } + } catch (Exception e) { + Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString()); + return new JSONArray(); + } + } + + /******************* + { + "type": "$key.remove", + "options": { + "index": 1 + } + } + *******************/ + public void remove(final JSONObject action, final JSONObject data, final JSONObject event, final Context context) { + JSONObject parsed = _parse(action, context); + try { + + Boolean isRemote = parsed.getBoolean("remote"); + String url = parsed.getString("url"); + if (isRemote) { + // remote + // cannot remove from remote + JSONObject error = new JSONObject(); + error.put("message", "You are not allowed to remove keys remotely"); + JasonHelper.next("error", action, error, event, context); + } else { + // local + keys = new SecurePreferences(context); + + try { + // Get {"items": [...]} from preferences + JSONArray items = _deserialize(url); + + // Remove item at index + if (action.has("options") && action.getJSONObject("options").has("index")) { + int index = action.getJSONObject("options").getInt("index"); + JSONArray new_items = new JSONArray(); + if (items.length() > index) { + for(int i=0; i index) { + if (action.getJSONObject("options").has("components")) { + JSONArray components_to_update = action.getJSONObject("options").getJSONArray("components"); + + JSONObject old_item = items.getJSONObject(index); + JSONArray old_components = old_item.getJSONArray("components"); + + for(int i=0; i Date: Sun, 26 Nov 2017 21:08:26 -0800 Subject: [PATCH 02/10] Use service for faster key query/manipulation --- .../jasonette/seed/Action/JasonKeyAction.java | 421 +---------------- .../com/jasonette/seed/Launcher/Launcher.java | 13 + .../seed/Service/key/JasonKeyService.java | 439 ++++++++++++++++++ 3 files changed, 463 insertions(+), 410 deletions(-) create mode 100644 app/src/main/java/com/jasonette/seed/Service/key/JasonKeyService.java diff --git a/app/src/main/java/com/jasonette/seed/Action/JasonKeyAction.java b/app/src/main/java/com/jasonette/seed/Action/JasonKeyAction.java index 42e40aa8..57ace26f 100644 --- a/app/src/main/java/com/jasonette/seed/Action/JasonKeyAction.java +++ b/app/src/main/java/com/jasonette/seed/Action/JasonKeyAction.java @@ -1,427 +1,28 @@ package com.jasonette.seed.Action; - import android.content.Context; -import android.content.SharedPreferences; -import android.util.Log; - -import com.jasonette.seed.Core.JasonViewActivity; -import com.jasonette.seed.Helper.JasonHelper; -import com.securepreferences.SecurePreferences; - -import org.json.JSONArray; +import com.jasonette.seed.Launcher.Launcher; import org.json.JSONObject; public class JasonKeyAction { - SharedPreferences keys; - - public JSONObject _parse(final JSONObject action, Context context) { - JSONObject res = new JSONObject(); - try { - if (action.has("options")) { - JSONObject options = action.getJSONObject("options"); - if (options.has("url")) { - res.put("url", options.getString("url")); - res.put("remote", true); - } else { - res.put("url", ((JasonViewActivity)context).url); - res.put("remote", false); - } - } else { - res.put("url", ((JasonViewActivity)context).url); - res.put("remote", false); - } - } catch (Exception e) { - Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString()); - } - return res; - } - private void _fetch(JSONObject action, JSONObject event, JSONObject parsed, Context context) { - - keys = new SecurePreferences(context); - - try { - String serialized = keys.getString(parsed.getString("url"), "{}"); - JSONObject deserialized = new JSONObject(serialized); - /* - - deserialized := { - "items": [{ - ... - }, { - ... - }, { - ... - }] - } - - */ - - Boolean isRemote = parsed.getBoolean("remote"); - JSONArray items; - if (!deserialized.has("items")) { - items = new JSONArray(); - } else { - items = deserialized.getJSONArray("items"); - if (isRemote) { - // Need to filter only the public attributes - JSONArray filtered_items = new JSONArray(); - for (int i = 0; i < items.length(); i++) { - JSONObject item = items.getJSONObject(i); - JSONArray components = item.getJSONArray("components"); - JSONArray filtered_components = new JSONArray(); - for (int j = 0; j < components.length(); j++) { - JSONObject component = components.getJSONObject(j); - if (component.has("read")) { - if (component.getString("read").equalsIgnoreCase("public")) { - // "read": "public" component - // Add to filtered_components - filtered_components.put(component); - } - } - } - - JSONObject filtered_item = new JSONObject(); - filtered_item.put("components", filtered_components); - - filtered_items.put(filtered_item); - } - - items = filtered_items; - - - } else { - // Return the full object - // so don't do anything - } - } - - JSONObject res = new JSONObject(); - res.put("items", items); - - JasonHelper.next("success", action, res, event, context); - // Filter only the "read - } catch (Exception e) { - Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString()); - } - - } - - - /** - - 1. Local Request - - { - "type": "$key.request" - } - - 2. Remote Request - - { - "type": "$key.request", - "options": { - "url": "file://wallet.json" - } - } - - **/ public void request(final JSONObject action, final JSONObject data, final JSONObject event, final Context context) { - JSONObject parsed = _parse(action, context); - try { - Boolean isRemote = parsed.getBoolean("remote"); - if (isRemote) { - // remote. - // fetch only the public attributes. - _fetch(action, event, parsed, context); - } else { - // local - // fetch full key items - _fetch(action, event, parsed, context); - } - } catch (Exception e) { - Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString()); - } - + _forward("request", action, data, event, context); } - - /******************* - { - "type": "$key.add", - "options": { - "components": [{ - "key": "type", - "val": "ETH" - }, { - "key": "publickey", - "val": "0xjdnfenfkdewfhk384b4" - }, { - "key": "name", - "val": "Ethereum" - }, { - "key": "privatekey", - "val": "0x8dbgjenb8fngjwev742gfh47gh8ds87fh3bv" - }] - } - } - *******************/ public void add(final JSONObject action, final JSONObject data, final JSONObject event, final Context context) { - JSONObject parsed = _parse(action, context); - try { - Boolean isRemote = parsed.getBoolean("remote"); - String url = parsed.getString("url"); - - if (!action.has("options")) { - JSONObject error = new JSONObject(); - error.put("message", "Must specify an item to add"); - JasonHelper.next("error", action, error, event, context); - return; - } - - if (!action.getJSONObject("options").has("components")) { - JSONObject error = new JSONObject(); - error.put("message", "A key item must have at least one component"); - JasonHelper.next("error", action, error, event, context); - return; - } - - if (isRemote) { - // remote. - // cannot add from remote - // 1. Construct error - JSONObject error = new JSONObject(); - error.put("message", "You are not allowed to add keys remotely"); - // 2. Trigger error callback - JasonHelper.next("error", action, error, event, context); - } else { - // local - keys = new SecurePreferences(context); - - try { - // Get {"items": [...]} from preferences - JSONArray items = _deserialize(url); - - // Add options object to the "items" array - JSONObject options = action.getJSONObject("options"); - items.put(options); - - JSONObject res = _serialize(url, items); - - // Return the updated {"items": [...]} as a return value - JasonHelper.next("success", action, res, event, context); - - } catch (Exception e) { - Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString()); - } - } - } catch (Exception e) { - Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString()); - } - - } - - - private JSONObject _serialize(String url, JSONArray items) { - try { - // update the {"items": [...]} with the new "items" array - JSONObject res = new JSONObject(); - res.put("items", items); - - // Update preference with the items - SharedPreferences.Editor editor = keys.edit(); - editor.putString(url, res.toString()); - editor.commit(); - return res; - - } catch (Exception e) { - Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString()); - return new JSONObject(); - } - } - private JSONArray _deserialize(String url) { - try { - String serialized = keys.getString(url, "{}"); - JSONObject deserialized = new JSONObject(serialized); - if (deserialized.has("items")) { - JSONArray items = deserialized.getJSONArray("items"); - return items; - } else { - return new JSONArray(); - } - } catch (Exception e) { - Log.d("Warning", e.getStackTrace()[0].getMethodName() + " : " + e.toString()); - return new JSONArray(); - } + _forward("add", action, data, event, context); } - - /******************* - { - "type": "$key.remove", - "options": { - "index": 1 - } - } - *******************/ public void remove(final JSONObject action, final JSONObject data, final JSONObject event, final Context context) { - JSONObject parsed = _parse(action, context); - try { - - Boolean isRemote = parsed.getBoolean("remote"); - String url = parsed.getString("url"); - if (isRemote) { - // remote - // cannot remove from remote - JSONObject error = new JSONObject(); - error.put("message", "You are not allowed to remove keys remotely"); - JasonHelper.next("error", action, error, event, context); - } else { - // local - keys = new SecurePreferences(context); - - try { - // Get {"items": [...]} from preferences - JSONArray items = _deserialize(url); - - // Remove item at index - if (action.has("options") && action.getJSONObject("options").has("index")) { - int index = action.getJSONObject("options").getInt("index"); - JSONArray new_items = new JSONArray(); - if (items.length() > index) { - for(int i=0; i index) { - if (action.getJSONObject("options").has("components")) { - JSONArray components_to_update = action.getJSONObject("options").getJSONArray("components"); - - JSONObject old_item = items.getJSONObject(index); - JSONArray old_components = old_item.getJSONArray("components"); - - for(int i=0; i index) { + for(int i=0; i index) { + if (action.getJSONObject("options").has("components")) { + JSONArray components_to_update = action.getJSONObject("options").getJSONArray("components"); + + JSONObject old_item = items.getJSONObject(index); + JSONArray old_components = old_item.getJSONArray("components"); + + for(int i=0; i Date: Mon, 27 Nov 2017 19:47:15 -0800 Subject: [PATCH 03/10] Added password protection for $keys --- app/build.gradle | 1 + app/src/debug/AndroidManifest.xml | 1 + app/src/main/AndroidManifest.xml | 1 + .../jasonette/seed/Action/JasonKeyAction.java | 45 +++ .../com/jasonette/seed/Launcher/Launcher.java | 2 +- .../jasonette/seed/Lib/PasscodeActivity.java | 117 ++++++++ .../seed/Service/key/JasonKeyService.java | 267 +++++++++++++----- 7 files changed, 367 insertions(+), 67 deletions(-) create mode 100644 app/src/main/java/com/jasonette/seed/Lib/PasscodeActivity.java diff --git a/app/build.gradle b/app/build.gradle index 38817ac9..e184e615 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -48,4 +48,5 @@ dependencies { compile 'com.jakewharton.timber:timber:4.5.1' compile 'com.google.android.gms:play-services:+' compile 'com.scottyab:secure-preferences-lib:0.1.4' + compile 'com.github.gliechtenstein:PasscodeView:master' } diff --git a/app/src/debug/AndroidManifest.xml b/app/src/debug/AndroidManifest.xml index 59153641..7d3aab00 100644 --- a/app/src/debug/AndroidManifest.xml +++ b/app/src/debug/AndroidManifest.xml @@ -41,6 +41,7 @@ android:name="com.commonsware.cwac.cam2.CameraActivity" android:process=":cwac_cam2" android:theme="@style/CameraTheme"/> +