Skip to content

Instantly share code, notes, and snippets.

@kaxline
Created October 30, 2021 15:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kaxline/99918c139c9d53cbe8d59a288ae164e8 to your computer and use it in GitHub Desktop.
Save kaxline/99918c139c9d53cbe8d59a288ae164e8 to your computer and use it in GitHub Desktop.
package io.re_public.android;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Callback;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.json.JSONObject;
import org.web3j.crypto.Keys;
import org.web3j.crypto.ECKeyPair;
import org.web3j.crypto.WalletUtils;
import org.web3j.exceptions.MessageDecodingException;
import org.web3j.utils.Numeric;
import java.io.File;
import java.math.BigInteger;
import java.security.Provider;
import java.security.SecureRandom;
import java.security.Security;
import android.Manifest;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.ApplicationInfo;
public class EthereumWalletModule extends ReactContextBaseJavaModule {
private SecureRandom random = new SecureRandom();
private Context mContext;
private void setupBouncyCastle() {
final Provider provider = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
if (provider == null) {
// Web3j will set up the provider lazily when it's first used.
return;
}
if (provider.getClass().equals(BouncyCastleProvider.class)) {
// BC with same package name, shouldn't happen in real life.
return;
}
// Android registers its own BC provider. As it might be outdated and might not include
// all needed ciphers, we substitute it with a known BC bundled in the app.
// Android's BC has its package rewritten to "com.android.org.bouncycastle" and because
// of that it's possible to have another BC implementation loaded in VM.
Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
Security.insertProviderAt(new BouncyCastleProvider(), 1);
}
EthereumWalletModule(ReactApplicationContext context) {
super(context);
setupBouncyCastle();
mContext = context;
}
private static JSONObject createEthereumAccount(String seed, String dataDir) {
JSONObject accountJson = new JSONObject();
try {
File fileDir = new File(dataDir);
if (!fileDir.exists()) {
fileDir.mkdirs();
}
ECKeyPair ecKeyPair = Keys.createEcKeyPair();
String filename = WalletUtils.generateWalletFile(seed, ecKeyPair, fileDir, false);
String privateKeyHexString = Numeric.encodeQuantity(ecKeyPair.getPrivateKey());
BigInteger decoded = Numeric.decodeQuantity(privateKeyHexString);
accountJson.put("filename", filename);
accountJson.put("privateKey", Numeric.encodeQuantity(ecKeyPair.getPrivateKey()));
accountJson.put("publicKey", Numeric.encodeQuantity(ecKeyPair.getPublicKey()));
} catch (MessageDecodingException e) {
return EthereumWalletModule.createEthereumAccount(seed, dataDir);
} catch (Exception e) {
e.printStackTrace();
}
return accountJson;
}
@Override
public String getName() {
return "EthereumWalletModule";
}
@ReactMethod
public void hasPermissions(Callback callback) {
AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
final int externalStorageMode = appOps.checkOpNoThrow(AppOpsManager.OPSTR_WRITE_EXTERNAL_STORAGE, android.os.Process.myUid(), mContext.getPackageName());
boolean granted = externalStorageMode == AppOpsManager.MODE_DEFAULT ?
(mContext.checkCallingOrSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
: (externalStorageMode == AppOpsManager.MODE_ALLOWED);
callback.invoke(granted);
}
@ReactMethod
public void createEthereumWallet(Callback callback) {
ApplicationInfo appInfo = getCurrentActivity().getApplicationInfo();
String dataDir = "no app info";
if (appInfo != null) {
dataDir = appInfo.dataDir;
}
String seed = new BigInteger(130, random).toString(32);
JSONObject result = createEthereumAccount(seed, dataDir);
callback.invoke(result.toString());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment