Skip to content

Commit

Permalink
Merge branch 'staging'
Browse files Browse the repository at this point in the history
  • Loading branch information
peachbits committed Feb 4, 2023
2 parents 4564a86 + 7bd2378 commit 195dff0
Show file tree
Hide file tree
Showing 219 changed files with 5,436 additions and 4,237 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ coverage/

# Generated headers
/android/app/src/main/java/co/edgesecure/app/EdgeApiKey.java
/ios/edge/edgeApiKey.h
/ios/EdgeApiKey.swift

# Checkpoint jsons
/android/app/src/main/assets/saplingtree/
Expand Down
73 changes: 73 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,78 @@
# edge-react-gui

## 3.2.0 (2023-02-02)

- Add max swap support
- Banxa: Add Google Pay support
- Change "Request" text to "Receive"
- Tron: Add note support
- HBAR: Fix balance syncing
- HBAR: Update block explorer
- XMR: Add max send
- Use SendScene2 for deeplink and EdgeProvider payments
- Add exit button to side menu
- Add marketing notification opt-out switch
- Round amounts for fiat conversion in SendScene/ExchangedFlipInput instead of truncating
- Lock send scene slider until all makeSpend requests are resolved
- Fix treatment of EdgeTransaction confirmations in TransactionRow
- Fix using label param in URI to tag transactions
- Fix spending previously entered amount
- Add edge-currency-accountbased as native module
- Add background gradient orientation to theme
- Replace Actions usage with navigation
- Show "Delete Account" option when settings are locked
- Update translations
- Various visual and performance fixes
- Upgrade edge-core-js to v0.19.40
- added: New 'syncing' to confirmations API
- fixed: Bug in validateConfirmations function incorrectly inferring a transaction as 'dropped'
- fixed: Re-publish with missing files.
- changed: Make sensitive account & wallet properties, like keys, non-enumerable.
- changed: Use the pluginId as the wallet logging prefix, instead of the currency code.
- Upgrade edge-currency-accountbased to v0.22.4
- Convert library to React Native Module
- This package will automatically install itself using React Native autolinking and no longer requires Webpack for integration
- Plugins are broken out and can be loaded individually
- Move checkpoint files to android folder
- Stub away unwanted USB modules
- Cleanup old and redundant dependency resolutions
- Changed: Implement accelerate transaction feature using new core API
- fixed: Adjust build settings to provide better support for iPhone 12.
- fixed: Track EVM wallet connections at the EdgeCurrencyTools level, to prevent active connections from disappearing.
- ARRR: Remove address explorer url
- EVM: Revert getMaxSpendable simplification changes in favor of recursion due to sliding standard fee scale
- DOT: Update @polkadot/api to v9.11.3
- DOT: Improve type safety and various code cleanups
- DOT: Add hard limit of 1 to transaction query progress
- HBAR: Update explorer urls
- TRX: Fix resource handling
- TRX: Fix fee calculation for low value transactions
- TRX: Add note support
- TRX: Update derivation path to industry standard
- XRP: Replace use of autofill with local transaction creation
- XRP: Replace currency settings with networkInfo
- XRP: Clean up code for type-safety
- XRP: Add broadcast failure handling
- Replace forked ethereumjs-wallet library
- EOS: Fix destructure error when attempting to spend
- EVM: Remove recursion from getMaxSpendable
- Replace remaining json-schema usage with cleaners
- Update checkpoint files
- Upgrade edge-currency-monero to v0.5.5
- Add getMaxSpendable
- Upgrade edge-core-js to v0.19.36
- Upgrade edge-currency-plugins to v1.3.6
- Fixed: Reduce the KEEP_ALIVE_MS blockbook server heartbeat time
- Upgrade edge-exchange-plugins to v0.17.0
- Add 'max' support across all swap plugins
- Remove legacy address fallback
- Godex: Add early exit for unsupported chains
- Remove Switchain
- Upgrade edge-core-js to v0.19.37
- Upgrade edge-login-ui-rn to v0.10.19
- Upgrade Changed: Orient background gradient using Theme
- Added: A new RequestPermissionsModal with toggles to opt-in for marketing and/or price notifications.

## 3.1.0 (2023-01-13)

- Add Bech32 address support
Expand Down
5 changes: 4 additions & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,11 @@ dependencies {
}

// Edge additions:
implementation 'androidx.work:work-runtime:2.7.1'
api 'com.google.guava:guava:31.0.1-android'
implementation 'androidx.work:work-runtime:2.7.1'

// We need to keep this in sync with the version in react-native-firebase:
implementation "com.google.firebase:firebase-messaging:23.0.0"

// If your app supports Android versions before Ice Cream Sandwich (API level 14)
implementation 'com.facebook.fresco:animated-base-support:1.3.0'
Expand Down
58 changes: 58 additions & 0 deletions android/app/src/main/java/co/edgesecure/app/Base58.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package co.edgesecure.app;

class Base58 {
public static String encode(byte data[]) {
// Data iterator:
int i = 0;

// Count leading zeroes:
int zeroes = 0;
while (i < data.length && data[i] == 0) {
zeroes++;
i++;
}

// ln 256 / ln 58 = 1.3657:
int maxDigits = (data.length + 1 - zeroes) * 137 / 100;

// The base58 digits, stored in little endian:
int digits[] = new int[maxDigits];
int digitsUsed = 0;

// For each input byte, we want to multiply the digits array by 256,
// then add the byte.
while (i < data.length) {
int carry = 0xff & data[i];
int j = 0;
while (j < digitsUsed || carry != 0) {
carry += digits[j] << 8;
digits[j] = carry % 58;
carry /= 58;
j++;
}
if (j > digitsUsed) digitsUsed = j;
i++;
}

// Now we have the digits in base58, but we need to stringify them:
char[] out = new char[zeroes + digitsUsed];
int j = 0;
while (j < zeroes) {
out[j] = BASE58[0];
j++;
}
while (j < out.length) {
digitsUsed--;
out[j] = BASE58[digits[digitsUsed]];
j++;
}
return new String(out);
}

private static final char[] BASE58 = {
'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K',
'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e',
'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
'z'
};
}
202 changes: 202 additions & 0 deletions android/app/src/main/java/co/edgesecure/app/EdgeCore.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
package co.edgesecure.app;

import android.content.Context;
import android.util.Base64;
import android.util.Log;
import androidx.annotation.NonNull;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class EdgeCore {
Context context;
String logId;

public EdgeCore(String logId, Context context) {
this.context = context;
this.logId = logId;
}

/**
* Fetches messages from the auth server, and returns an array of usernames with pending logins.
*/
public @NonNull Iterable<String> fetchPendingLogins() throws JSONException, IOException {
File basePath = context.getFilesDir();
File loginsPath = new File(basePath, "logins");
File[] files = loginsPath.listFiles();

// Load the files:
HashMap<String, String> loginIds = new HashMap();
for (File file : files) {
try {
JSONObject json = new JSONObject(readFile(file));
if (!json.has("loginAuthBox")) continue;
String loginId = json.getString("loginId");
String username = json.getString("username");
loginIds.put(loginId, username);
} catch (Exception e) {
continue;
}
}

// Bail out if there are no logged-in users:
if (loginIds.size() == 0) return new ArrayList();

// Prepare our payload:
JSONObject payloadJson = new JSONObject();
payloadJson.put("loginIds", new JSONArray(loginIds.keySet()));

// Do the request:
String uri = "https://auth.airbitz.co/api/v2/messages";
JSONObject replyJson = new JSONObject(authFetch(uri, payloadJson.toString()));

// Validate the response:
int statusCode = replyJson.getInt("status_code");
if (statusCode != 0) throw new JSONException("Incorrect status code");
JSONArray messages = replyJson.getJSONArray("results");

// Find messages with problems:
ArrayList<String> problemUsers = new ArrayList();
int messagesLength = messages.length();
for (int i = 0; i < messagesLength; ++i) {
JSONObject message = messages.getJSONObject(i);
String loginId = message.getString("loginId");
String username = loginIds.get(loginId);
if (username == null) continue;

JSONArray pendingVouchers = message.optJSONArray("pendingVouchers");
boolean hasVoucher = pendingVouchers != null && pendingVouchers.length() > 0;
boolean hasReset = message.optBoolean("otpResetPending", false);

if (hasVoucher || hasReset) {
problemUsers.add(username);
}
}

return problemUsers;
}

public void updatePushToken(String token) throws JSONException, IOException {
// Read the clientId:
File basePath = context.getFilesDir();
File file = new File(basePath, "client.json");
JSONObject json = new JSONObject(readFile(file));
String clientId64 = json.getString("clientId");
String clientId = Base58.encode(Base64.decode(clientId64, Base64.DEFAULT));

// Prepare our payload:
JSONObject payloadJson = new JSONObject();
payloadJson.put("apiKey", EdgeApiKey.apiKey);
payloadJson.put("deviceId", clientId);
payloadJson.put("deviceToken", token);

// Do the request:
String uri = EdgeApiKey.pushServer.concat("/v2/device/");
pushFetch(uri, payloadJson.toString());
}

/** Does a request / reply with the auth server. */
private String authFetch(String uri, String body) throws IOException {
HttpsURLConnection connection = null;
try {
// Set up the HTTPS connection:
connection = (HttpsURLConnection) new URL(uri).openConnection();
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
connection.setSSLSocketFactory(context.getSocketFactory());

// Add the auth server headers:
byte[] bodyData = body.getBytes("UTF-8");
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Authorization", "Token " + EdgeApiKey.apiKey);
connection.setRequestProperty("Content-Length", Integer.toString(bodyData.length));
connection.setRequestMethod("POST");
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);

// Send the body:
OutputStream wr = connection.getOutputStream();
wr.write(bodyData);
wr.flush();
wr.close();
connection.connect();

Log.i(logId, String.format("%s %d", uri, connection.getResponseCode()));

// Read the reply body:
return readInputStream(connection.getInputStream());
} catch (Exception e) {
throw new IOException("Could not reach auth server " + uri, e);
} finally {
if (connection != null) connection.disconnect();
}
}

/** Does a request / reply with the push server. */
private void pushFetch(String uri, String body) throws IOException {
HttpsURLConnection connection = null;
try {
// Set up the HTTPS connection:
connection = (HttpsURLConnection) new URL(uri).openConnection();
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, null, null);
connection.setSSLSocketFactory(context.getSocketFactory());

// Add the auth server headers:
byte[] bodyData = body.getBytes("UTF-8");
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Content-Length", Integer.toString(bodyData.length));
connection.setRequestMethod("POST");
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);

// Send the body:
OutputStream wr = connection.getOutputStream();
wr.write(bodyData);
wr.flush();
wr.close();
connection.connect();

Log.i(logId, String.format("%s %d", uri, connection.getResponseCode()));
} catch (Exception e) {
throw new IOException("Could not reach push server " + uri, e);
} finally {
if (connection != null) connection.disconnect();
}
}

/** Reads a file from disk. */
private static @NonNull String readFile(File file) throws IOException {
try (FileInputStream stream = new FileInputStream(file)) {
return readInputStream(stream);
}
}

/** Reads an input stream into a string, as utf-8. */
private static @NonNull String readInputStream(@NonNull InputStream stream) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();

int size;
byte[] data = new byte[4096];
while ((size = stream.read(data)) > 0) {
out.write(data, 0, size);
}

return out.toString("UTF-8");
}
}
2 changes: 0 additions & 2 deletions android/app/src/main/java/co/edgesecure/app/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
import android.os.Bundle;
import com.facebook.react.ReactActivity;
import com.reactnativecomponent.splashscreen.RCTSplashScreen;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;

public class MainActivity extends ReactActivity {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import android.app.Application;
import android.content.Context;
import android.webkit.WebView;
import com.bugsnag.android.BreadcrumbType;
import com.bugsnag.android.Bugsnag;
import com.bugsnag.android.Configuration;
Expand All @@ -11,13 +10,13 @@
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JSIModulePackage;
import com.facebook.react.modules.i18nmanager.I18nUtil;
import com.facebook.soloader.SoLoader;
import com.swmansion.reanimated.ReanimatedJSIModulePackage;
import java.lang.reflect.InvocationTargetException;
import java.util.HashSet;
import java.util.List;
import com.facebook.react.bridge.JSIModulePackage;
import com.swmansion.reanimated.ReanimatedJSIModulePackage;

public class MainApplication extends Application implements ReactApplication {

Expand Down
Loading

0 comments on commit 195dff0

Please sign in to comment.