Skip to content

Commit d0e5294

Browse files
authored
Merge pull request #2 from cawfree/develop
0.1.1
2 parents 7a7a4c4 + 63c6199 commit d0e5294

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+1562
-212
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# OSX
22
#
33
.DS_Store
4+
android/src/main/java/io/github/cawfree/web3/javac*
45

56
# node.js
67
#

README.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
<p align="center">
1+
<div align="center">
22
<a href="https://github.com/cawfree/web3-react-native" alt="web3-react-native">
3-
<img src="./public/logo.png" width="640" height="452" />
3+
<img src="./public/logo.png" width="320" height="226" />
44
</a>
5-
</p>
5+
</div>
66

77
# web3-react-native
88
[**Web3**](https://web3js.readthedocs.io/en/v1.2.6/) Native Modules for [**React Native**](https://reactnative.dev/).
@@ -35,6 +35,14 @@ pod 'web3swift', '2.2.1', :modular_headers => true
3535
> ⚠️ This is an ugly workaround for existing definition constraints in the [Podspec](https://github.com/cawfree/web3-react-native/blob/63664f366c436aed73083b6b0a5cbf0b7374bfd3/web3-react-native.podspec#L26). ([View Issue](https://github.com/cawfree/web3-react-native/issues/1)).
3636
3737
### Android
38+
In your app's `AndroidManifest.xml`, [you need to](https://github.com/web3j/web3j/issues/915) enable [`android:largeHeap](https://developer.android.com/guide/topics/manifest/application-element)` under the `<application>` tag:
39+
40+
```diff
41+
<application
42+
+ android:largeHeap="true"
43+
/>
44+
```
45+
3846
Perform a rebuild of your compiled application by calling `react-native run-android`.
3947

4048
For usage details, please see the [**documentation**](./docs).
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
/**
2+
* Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
3+
*
4+
* You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
5+
* copy, modify, and distribute this software in source code or binary form for use
6+
* in connection with the web services and APIs provided by Facebook.
7+
*
8+
* As with any software that integrates with the Facebook platform, your use of
9+
* this software is subject to the Facebook Developer Principles and Policies
10+
* [http://developers.facebook.com/policy/]. This copyright notice shall be
11+
* included in all copies or substantial portions of the software.
12+
*
13+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19+
*/
20+
21+
package io.github.cawfree.web3;
22+
23+
import android.os.Bundle;
24+
import org.json.JSONArray;
25+
import org.json.JSONException;
26+
import org.json.JSONObject;
27+
28+
import java.util.*;
29+
30+
/**
31+
* com.facebook.internal is solely for the use of other packages within the Facebook SDK for
32+
* Android. Use of any of the classes in this package is unsupported, and they may be modified or
33+
* removed without warning at any time.
34+
*
35+
* A helper class that can round trip between JSON and Bundle objects that contains the types:
36+
* Boolean, Integer, Long, Double, String
37+
* If other types are found, an IllegalArgumentException is thrown.
38+
*/
39+
public class BundleJSONConverter {
40+
private static final Map<Class<?>, Setter> SETTERS = new HashMap<Class<?>, Setter>();
41+
42+
static {
43+
SETTERS.put(Boolean.class, new Setter() {
44+
public void setOnBundle(Bundle bundle, String key, Object value) throws JSONException {
45+
bundle.putBoolean(key, (Boolean) value);
46+
}
47+
48+
public void setOnJSON(JSONObject json, String key, Object value) throws JSONException {
49+
json.put(key, value);
50+
}
51+
});
52+
SETTERS.put(Integer.class, new Setter() {
53+
public void setOnBundle(Bundle bundle, String key, Object value) throws JSONException {
54+
bundle.putInt(key, (Integer) value);
55+
}
56+
57+
public void setOnJSON(JSONObject json, String key, Object value) throws JSONException {
58+
json.put(key, value);
59+
}
60+
});
61+
SETTERS.put(Long.class, new Setter() {
62+
public void setOnBundle(Bundle bundle, String key, Object value) throws JSONException {
63+
bundle.putLong(key, (Long) value);
64+
}
65+
66+
public void setOnJSON(JSONObject json, String key, Object value) throws JSONException {
67+
json.put(key, value);
68+
}
69+
});
70+
SETTERS.put(Double.class, new Setter() {
71+
public void setOnBundle(Bundle bundle, String key, Object value) throws JSONException {
72+
bundle.putDouble(key, (Double) value);
73+
}
74+
75+
public void setOnJSON(JSONObject json, String key, Object value) throws JSONException {
76+
json.put(key, value);
77+
}
78+
});
79+
SETTERS.put(String.class, new Setter() {
80+
public void setOnBundle(Bundle bundle, String key, Object value) throws JSONException {
81+
bundle.putString(key, (String) value);
82+
}
83+
84+
public void setOnJSON(JSONObject json, String key, Object value) throws JSONException {
85+
json.put(key, value);
86+
}
87+
});
88+
SETTERS.put(String[].class, new Setter() {
89+
public void setOnBundle(Bundle bundle, String key, Object value) throws JSONException {
90+
throw new IllegalArgumentException("Unexpected type from JSON");
91+
}
92+
93+
public void setOnJSON(JSONObject json, String key, Object value) throws JSONException {
94+
JSONArray jsonArray = new JSONArray();
95+
for (String stringValue : (String[])value) {
96+
jsonArray.put(stringValue);
97+
}
98+
json.put(key, jsonArray);
99+
}
100+
});
101+
102+
SETTERS.put(JSONArray.class, new Setter() {
103+
public void setOnBundle(Bundle bundle, String key, Object value) throws JSONException {
104+
JSONArray jsonArray = (JSONArray)value;
105+
ArrayList<String> stringArrayList = new ArrayList<String>();
106+
// Empty list, can't even figure out the type, assume an ArrayList<String>
107+
if (jsonArray.length() == 0) {
108+
bundle.putStringArrayList(key, stringArrayList);
109+
return;
110+
}
111+
112+
// Only strings are supported for now
113+
for (int i = 0; i < jsonArray.length(); i++) {
114+
Object current = jsonArray.get(i);
115+
if (current instanceof String) {
116+
stringArrayList.add((String)current);
117+
} else {
118+
throw new IllegalArgumentException("Unexpected type in an array: " + current.getClass());
119+
}
120+
}
121+
bundle.putStringArrayList(key, stringArrayList);
122+
}
123+
124+
@Override
125+
public void setOnJSON(JSONObject json, String key, Object value) throws JSONException {
126+
throw new IllegalArgumentException("JSONArray's are not supported in bundles.");
127+
}
128+
});
129+
}
130+
131+
public interface Setter {
132+
public void setOnBundle(Bundle bundle, String key, Object value) throws JSONException;
133+
public void setOnJSON(JSONObject json, String key, Object value) throws JSONException;
134+
}
135+
136+
public static JSONObject convertToJSON(Bundle bundle) throws JSONException {
137+
JSONObject json = new JSONObject();
138+
139+
for(String key : bundle.keySet()) {
140+
Object value = bundle.get(key);
141+
if (value == null) {
142+
// Null is not supported.
143+
continue;
144+
}
145+
146+
// Special case List<String> as getClass would not work, since List is an interface
147+
if (value instanceof List<?>) {
148+
JSONArray jsonArray = new JSONArray();
149+
@SuppressWarnings("unchecked")
150+
List<String> listValue = (List<String>)value;
151+
for (String stringValue : listValue) {
152+
jsonArray.put(stringValue);
153+
}
154+
json.put(key, jsonArray);
155+
continue;
156+
}
157+
158+
// Special case Bundle as it's one way, on the return it will be JSONObject
159+
if (value instanceof Bundle) {
160+
json.put(key, convertToJSON((Bundle)value));
161+
continue;
162+
}
163+
164+
Setter setter = SETTERS.get(value.getClass());
165+
if (setter == null) {
166+
throw new IllegalArgumentException("Unsupported type: " + value.getClass());
167+
}
168+
setter.setOnJSON(json, key, value);
169+
}
170+
171+
return json;
172+
}
173+
174+
public static Bundle convertToBundle(JSONObject jsonObject) throws JSONException {
175+
Bundle bundle = new Bundle();
176+
@SuppressWarnings("unchecked")
177+
Iterator<String> jsonIterator = jsonObject.keys();
178+
while (jsonIterator.hasNext()) {
179+
String key = jsonIterator.next();
180+
Object value = jsonObject.get(key);
181+
if (value == null || value == JSONObject.NULL) {
182+
// Null is not supported.
183+
continue;
184+
}
185+
186+
// Special case JSONObject as it's one way, on the return it would be Bundle.
187+
if (value instanceof JSONObject) {
188+
bundle.putBundle(key, convertToBundle((JSONObject)value));
189+
continue;
190+
}
191+
192+
Setter setter = SETTERS.get(value.getClass());
193+
if (setter == null) {
194+
throw new IllegalArgumentException("Unsupported type: " + value.getClass());
195+
}
196+
setter.setOnBundle(bundle, key, value);
197+
}
198+
199+
return bundle;
200+
}
201+
}

android/src/main/java/io/github/cawfree/web3/Web3Module.java

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,20 @@
2222

2323
import org.json.JSONObject;
2424

25+
import java.security.Security;
26+
import java.security.Provider;
27+
import org.bouncycastle.jce.provider.BouncyCastleProvider;
28+
2529
import java.io.File;
2630
import java.io.IOException;
2731
import java.io.FileWriter;
32+
import java.io.FileReader;
33+
import java.io.BufferedReader;
2834
import java.util.UUID;
2935
import java.util.Map;
3036
import java.util.HashMap;
3137
import java.math.BigDecimal;
38+
import java.lang.StringBuilder;
3239

3340
// TODO: Remove this!
3441
import android.util.Log;
@@ -49,6 +56,16 @@ private static final void debug(final String pString) {
4956
/* Member Variables. */
5057
private final Map<String, Credentials> mWallets;
5158

59+
// https://github.com/web3j/web3j/issues/915#issuecomment-483145928
60+
private static final void setupBouncyCastle() {
61+
final Provider p = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
62+
if (p == null || p.getClass().equals(BouncyCastleProvider.class)) {
63+
return;
64+
}
65+
Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
66+
Security.insertProviderAt(new BouncyCastleProvider(), 1);
67+
}
68+
5269
/** Constructor */
5370
public Web3Module(final ReactApplicationContext pReactApplicationContext) {
5471
super(pReactApplicationContext);
@@ -59,6 +76,29 @@ public Web3Module(final ReactApplicationContext pReactApplicationContext) {
5976
/** Module name when imported via NativeModules. **/
6077
@Override public String getName() { return "Web3"; }
6178

79+
@ReactMethod
80+
public final void createKeystore(final String pPassword, final Promise pPromise) {
81+
try {
82+
// Setup Bouncy Castle.
83+
Web3Module.setupBouncyCastle();
84+
// Fetch the cache directory.
85+
final File dir = this.getReactApplicationContext().getCacheDir();
86+
// Generate the new Wallet.
87+
final String name = WalletUtils.generateNewWalletFile(pPassword, dir);
88+
final File f = new File(dir.getAbsolutePath() + File.separator + name);
89+
// Parse the Keystore into a JSONObject.
90+
final JSONObject ks = new JSONObject(Web3Module.readFile(f));
91+
// Delete the temporary file.
92+
f.delete();
93+
// Propagate the keystore back to the caller.
94+
pPromise.resolve(Arguments.fromBundle(new BundleJSONConverter().convertToBundle(ks)));
95+
}
96+
catch (final Exception pException) {
97+
pPromise.reject(pException);
98+
}
99+
return;
100+
}
101+
62102
@ReactMethod
63103
public final void loadWallet(final ReadableMap pKeystore, final String pPassword, final Promise pPromise) {
64104
try {
@@ -109,25 +149,39 @@ public final void sendFunds(final ReadableMap pWallet, final String pUrl, final
109149
return;
110150
}
111151

152+
/** Reads the string contents of a File. **/
153+
private static final String readFile(final File pFile) throws IOException {
154+
final StringBuilder sb = new StringBuilder();
155+
final BufferedReader br = new BufferedReader(new FileReader(pFile));
156+
String s;
157+
while ((s = br.readLine()) != null) {
158+
sb.append(s);
159+
sb.append('\n');
160+
}
161+
br.close();
162+
return sb.toString();
163+
}
164+
112165
/** Writes string contents to a designated File. **/
113-
private void writeFile(final File pFile, final String pContent) throws IOException {
166+
private static final void writeFile(final File pFile, final String pContent) throws IOException {
114167
final FileWriter fw = new FileWriter(pFile, true);
115168
fw.write(pContent);
116169
// XXX: Ensure all of the bytes are written.
117170
fw.flush();
118171
fw.close();
119172
}
120173

174+
/** Creates a temporary file reference. **/
175+
private final File createTempFile() throws IOException {
176+
return File.createTempFile(UUID.randomUUID().toString(), "json", this.getReactApplicationContext().getCacheDir());
177+
}
178+
121179
/** Adds a Wallet to the in-memory map. */
122180
private final String addWallet(final ReadableMap pKeystore, final String pPassword) throws IOException, CipherException {
123-
final File f = File.createTempFile(
124-
UUID.randomUUID().toString(),
125-
"json",
126-
this.getReactApplicationContext().getCacheDir()
127-
);
181+
final File f = this.createTempFile();
128182
// XXX: Write the supplied data to a temporary file.
129183
// TODO: Use loadJsonCredentials.
130-
this.writeFile(f, new JSONObject(pKeystore.toHashMap()).toString());
184+
Web3Module.writeFile(f, new JSONObject(pKeystore.toHashMap()).toString());
131185

132186
// Load the Credentials.
133187
final Credentials c = WalletUtils.loadCredentials(pPassword, f.getAbsolutePath());

0 commit comments

Comments
 (0)