Updated on 2026-08-14
This commit is contained in:
parent
5c482bf194
commit
425a9019f2
9 changed files with 465 additions and 400 deletions
|
|
@ -1,4 +0,0 @@
|
|||
package com.tangem.data.DB;
|
||||
|
||||
public class Repository {
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
package com.tangem.data.network.model;
|
||||
|
||||
public class UserModel {
|
||||
}
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
package com.tangem.data.network.task.request_pin;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.security.keystore.KeyGenParameterSpec;
|
||||
import android.security.keystore.KeyPermanentlyInvalidatedException;
|
||||
import android.security.keystore.KeyProperties;
|
||||
|
||||
import com.tangem.domain.wallet.FingerprintHelper;
|
||||
import com.tangem.domain.wallet.PINStorage;
|
||||
import com.tangem.presentation.activity.RequestPINActivity;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
|
||||
public class StartFingerprintReaderTask extends AsyncTask<Void, Void, Boolean> {
|
||||
private WeakReference<RequestPINActivity> reference;
|
||||
|
||||
private KeyStore keyStore;
|
||||
private Cipher cipher;
|
||||
|
||||
private FingerprintManager.CryptoObject cryptoObject;
|
||||
|
||||
FingerprintManager fingerprintManager;
|
||||
FingerprintHelper fingerprintHelper;
|
||||
|
||||
RequestPINActivity activity;
|
||||
|
||||
public StartFingerprintReaderTask(RequestPINActivity activity, FingerprintManager fingerprintManager, FingerprintHelper fingerprintHelper) {
|
||||
reference = new WeakReference<>(activity);
|
||||
this.fingerprintManager = fingerprintManager;
|
||||
this.fingerprintHelper = fingerprintHelper;
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
if (!getKeyStore())
|
||||
return false;
|
||||
|
||||
if (!createNewKey(false))
|
||||
return false;
|
||||
|
||||
if (!getCipher())
|
||||
return false;
|
||||
|
||||
if (!initCipher(Cipher.DECRYPT_MODE))
|
||||
return false;
|
||||
|
||||
return initCryptObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final Boolean success) {
|
||||
RequestPINActivity requestPINActivity = reference.get();
|
||||
|
||||
onCancelled();
|
||||
|
||||
if (!success) {
|
||||
requestPINActivity.doLog("Authentication failed!");
|
||||
} else {
|
||||
fingerprintHelper.startAuth(fingerprintManager, cryptoObject);
|
||||
requestPINActivity.doLog("Authenticate using fingerprint!");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled() {
|
||||
RequestPINActivity requestPINActivity = reference.get();
|
||||
|
||||
requestPINActivity.mStartFingerprintReaderTask = null;
|
||||
}
|
||||
|
||||
private boolean getKeyStore() {
|
||||
RequestPINActivity requestPINActivity = reference.get();
|
||||
|
||||
requestPINActivity.doLog("Getting keystore...");
|
||||
try {
|
||||
keyStore = KeyStore.getInstance(RequestPINActivity.KEYSTORE);
|
||||
keyStore.load(null); // Create empty keystore
|
||||
return true;
|
||||
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
public boolean createNewKey(boolean forceCreate) {
|
||||
RequestPINActivity requestPINActivity = reference.get();
|
||||
|
||||
requestPINActivity.doLog("Creating new key...");
|
||||
try {
|
||||
if (forceCreate)
|
||||
keyStore.deleteEntry(RequestPINActivity.KEY_ALIAS);
|
||||
|
||||
if (!keyStore.containsAlias(RequestPINActivity.KEY_ALIAS)) {
|
||||
KeyGenerator generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, RequestPINActivity.KEYSTORE);
|
||||
|
||||
generator.init(new KeyGenParameterSpec.Builder(RequestPINActivity.KEY_ALIAS,
|
||||
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
|
||||
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
|
||||
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
|
||||
.setUserAuthenticationRequired(true)
|
||||
.build()
|
||||
);
|
||||
|
||||
generator.generateKey();
|
||||
requestPINActivity.doLog("Key created.");
|
||||
} else
|
||||
requestPINActivity.doLog("Key exists.");
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean getCipher() {
|
||||
RequestPINActivity requestPINActivity = reference.get();
|
||||
|
||||
requestPINActivity.doLog("Getting cipher...");
|
||||
try {
|
||||
cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
|
||||
return true;
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
private boolean initCipher(int mode) {
|
||||
RequestPINActivity requestPINActivity = reference.get();
|
||||
|
||||
requestPINActivity.doLog("Initializing cipher...");
|
||||
try {
|
||||
keyStore.load(null);
|
||||
SecretKey keyspec = (SecretKey) keyStore.getKey(RequestPINActivity.KEY_ALIAS, null);
|
||||
|
||||
if (mode == Cipher.ENCRYPT_MODE) {
|
||||
cipher.init(mode, keyspec);
|
||||
} else {
|
||||
byte[] iv = null;
|
||||
if (requestPINActivity.mode == RequestPINActivity.Mode.RequestPIN || activity.mode == RequestPINActivity.Mode.RequestNewPIN || activity.mode == RequestPINActivity.Mode.ConfirmNewPIN) {
|
||||
iv = PINStorage.loadEncryptedIV();
|
||||
} else if (activity.mode == RequestPINActivity.Mode.RequestPIN2 || activity.mode == RequestPINActivity.Mode.RequestNewPIN2 || activity.mode == RequestPINActivity.Mode.ConfirmNewPIN2) {
|
||||
iv = PINStorage.loadEncryptedIV2();
|
||||
}
|
||||
IvParameterSpec ivspec = new IvParameterSpec(iv);
|
||||
cipher.init(mode, keyspec, ivspec);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (KeyPermanentlyInvalidatedException e) {
|
||||
e.printStackTrace();
|
||||
createNewKey(true); // Retry after clearing entry
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
private boolean initCryptObject() {
|
||||
RequestPINActivity requestPINActivity = reference.get();
|
||||
|
||||
requestPINActivity.doLog("Initializing crypt object...");
|
||||
try {
|
||||
cryptoObject = new FingerprintManager.CryptoObject(cipher);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package com.tangem.data.network.task.save_pin;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.tangem.domain.wallet.FingerprintHelper;
|
||||
import com.tangem.presentation.activity.SavePINActivity;
|
||||
import com.tangem.wallet.R;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
public class ConfirmWithFingerprintTask extends AsyncTask<Void, Void, Boolean> {
|
||||
private WeakReference<SavePINActivity> reference;
|
||||
|
||||
public ConfirmWithFingerprintTask(SavePINActivity context) {
|
||||
reference = new WeakReference<>(context);
|
||||
|
||||
reference.get().fingerprintHelper = new FingerprintHelper(reference.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
SavePINActivity savePINActivity = reference.get();
|
||||
|
||||
if (!savePINActivity.getKeyStore())
|
||||
return false;
|
||||
|
||||
if (!savePINActivity.createNewKey(false))
|
||||
return false;
|
||||
|
||||
if (!savePINActivity.getCipher())
|
||||
return false;
|
||||
|
||||
return savePINActivity.initCipher(Cipher.ENCRYPT_MODE) && savePINActivity.initCryptObject();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final Boolean success) {
|
||||
SavePINActivity savePINActivity = reference.get();
|
||||
|
||||
onCancelled();
|
||||
|
||||
if (!success) {
|
||||
Toast.makeText(savePINActivity, R.string.pin_save_fail, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
savePINActivity.print("Confirm PIN action using fingerprint!");
|
||||
savePINActivity.fingerprintHelper.startAuth(savePINActivity.fingerprintManager, savePINActivity.cryptoObject);
|
||||
savePINActivity.CreateFingerPrintConfirmationDialog();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled() {
|
||||
SavePINActivity savePINActivity = reference.get();
|
||||
|
||||
savePINActivity.mConfirmWithFingerprintTask = null;
|
||||
if (savePINActivity.dFingerPrintConfirmation != null) {
|
||||
savePINActivity.dFingerPrintConfirmation.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
package com.tangem.data.network.task.send_transaction;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.tangem.data.network.request.ElectrumRequest;
|
||||
import com.tangem.data.network.task.ElectrumTask;
|
||||
import com.tangem.domain.wallet.Blockchain;
|
||||
import com.tangem.domain.wallet.CoinEngine;
|
||||
import com.tangem.domain.wallet.CoinEngineFactory;
|
||||
import com.tangem.domain.wallet.LastSignStorage;
|
||||
import com.tangem.domain.wallet.SharedData;
|
||||
import com.tangem.presentation.activity.SendTransactionActivity;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
public class ConnectTask extends ElectrumTask {
|
||||
private WeakReference<SendTransactionActivity> reference;
|
||||
|
||||
public ConnectTask(SendTransactionActivity context, String host, int port) {
|
||||
super(host, port);
|
||||
reference = new WeakReference<>(context);
|
||||
}
|
||||
|
||||
public ConnectTask(SendTransactionActivity context, String host, int port, SharedData sharedData) {
|
||||
super(host, port, sharedData);
|
||||
reference = new WeakReference<>(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Integer... values) {
|
||||
super.onProgressUpdate(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<ElectrumRequest> requests) {
|
||||
super.onPostExecute(requests);
|
||||
SendTransactionActivity sendTransactionActivity = reference.get();
|
||||
|
||||
CoinEngine engine = CoinEngineFactory.Create(Blockchain.Bitcoin);
|
||||
|
||||
for (ElectrumRequest request : requests) {
|
||||
try {
|
||||
if (request.error == null) {
|
||||
if (request.isMethod(ElectrumRequest.METHOD_SendTransaction)) {
|
||||
try {
|
||||
String hashTX = request.getResultString();
|
||||
|
||||
try {
|
||||
LastSignStorage.setLastMessage(sendTransactionActivity.mCard.getWallet(), hashTX);
|
||||
if (hashTX.startsWith("0x") || hashTX.startsWith("0X")) {
|
||||
hashTX = hashTX.substring(2);
|
||||
}
|
||||
BigInteger bigInt = new BigInteger(hashTX, 16); //TODO: очень плохой способ
|
||||
LastSignStorage.setTxWasSend(sendTransactionActivity.mCard.getWallet());
|
||||
LastSignStorage.setLastMessage(sendTransactionActivity.mCard.getWallet(), "");
|
||||
Log.e("TX_RESULT", hashTX);
|
||||
sendTransactionActivity.finishWithSuccess();
|
||||
} catch (Exception e) {
|
||||
engine.SwitchNode(null);
|
||||
sendTransactionActivity.finishWithError(hashTX);
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
engine.SwitchNode(null);
|
||||
sendTransactionActivity.finishWithError(e.toString());
|
||||
}
|
||||
}
|
||||
} else if (request.error != null) {
|
||||
engine.SwitchNode(null);
|
||||
sendTransactionActivity.finishWithError(request.error);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
engine.SwitchNode(null);
|
||||
sendTransactionActivity.finishWithError(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package com.tangem.data.network.task.send_transaction;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.tangem.data.network.request.InfuraRequest;
|
||||
import com.tangem.data.network.task.InfuraTask;
|
||||
import com.tangem.domain.wallet.Blockchain;
|
||||
import com.tangem.domain.wallet.LastSignStorage;
|
||||
import com.tangem.presentation.activity.SendTransactionActivity;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
public class ETHRequestTask extends InfuraTask {
|
||||
private WeakReference<SendTransactionActivity> reference;
|
||||
|
||||
public ETHRequestTask(SendTransactionActivity context, Blockchain blockchain) {
|
||||
super(blockchain);
|
||||
reference = new WeakReference<>(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<InfuraRequest> requests) {
|
||||
super.onPostExecute(requests);
|
||||
SendTransactionActivity sendTransactionActivity = reference.get();
|
||||
|
||||
for (InfuraRequest request : requests) {
|
||||
try {
|
||||
if (request.error == null) {
|
||||
if (request.isMethod(InfuraRequest.METHOD_ETH_SendRawTransaction)) {
|
||||
try {
|
||||
String hashTX = "";
|
||||
try {
|
||||
String tmp = request.getResultString();
|
||||
hashTX = tmp;
|
||||
} catch (JSONException e) {
|
||||
JSONObject msg = request.getAnswer();
|
||||
JSONObject err = msg.getJSONObject("error");
|
||||
hashTX = err.getString("message");
|
||||
LastSignStorage.setLastMessage(sendTransactionActivity.mCard.getWallet(), hashTX);
|
||||
sendTransactionActivity.finishWithError(hashTX);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (hashTX.startsWith("0x") || hashTX.startsWith("0X")) {
|
||||
hashTX = hashTX.substring(2);
|
||||
}
|
||||
BigInteger bigInt = new BigInteger(hashTX, 16); //TODO: очень плохой способ
|
||||
LastSignStorage.setTxWasSend(sendTransactionActivity.mCard.getWallet());
|
||||
LastSignStorage.setLastMessage(sendTransactionActivity.mCard.getWallet(), "");
|
||||
BigInteger nonce = sendTransactionActivity.mCard.GetConfirmTXCount();
|
||||
nonce.add(BigInteger.valueOf(1));
|
||||
sendTransactionActivity.mCard.SetConfirmTXCount(nonce);
|
||||
Log.e("TX_RESULT", hashTX);
|
||||
sendTransactionActivity.finishWithSuccess();
|
||||
} catch (Exception e) {
|
||||
sendTransactionActivity.finishWithError(hashTX);
|
||||
}
|
||||
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
sendTransactionActivity.finishWithError(e.toString());
|
||||
}
|
||||
}
|
||||
} else if (request.error != null) {
|
||||
sendTransactionActivity.finishWithError(request.error);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
sendTransactionActivity.finishWithError(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -10,12 +10,8 @@ import android.content.pm.PackageManager;
|
|||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.nfc.NfcAdapter;
|
||||
import android.nfc.Tag;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.security.keystore.KeyGenParameterSpec;
|
||||
import android.security.keystore.KeyPermanentlyInvalidatedException;
|
||||
import android.security.keystore.KeyProperties;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.text.TextUtils;
|
||||
|
|
@ -26,6 +22,7 @@ import android.widget.Button;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.tangem.data.network.task.request_pin.StartFingerprintReaderTask;
|
||||
import com.tangem.domain.cardReader.NfcManager;
|
||||
import com.tangem.domain.wallet.FingerprintHelper;
|
||||
import com.tangem.domain.wallet.PINStorage;
|
||||
|
|
@ -33,26 +30,18 @@ import com.tangem.domain.wallet.TangemCard;
|
|||
import com.tangem.wallet.R;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
|
||||
public class RequestPINActivity extends AppCompatActivity implements NfcAdapter.ReaderCallback, FingerprintHelper.FingerprintHelperListener {
|
||||
|
||||
public enum Mode {RequestPIN, RequestPIN2, RequestNewPIN, RequestNewPIN2, ConfirmNewPIN, ConfirmNewPIN2}
|
||||
|
||||
Mode mode;
|
||||
public Mode mode;
|
||||
boolean allowFingerprint = false;
|
||||
private NfcManager mNfcManager;
|
||||
private TextView tvPIN;
|
||||
private StartFingerprintReaderTask mStartFingerprintReaderTask;
|
||||
public StartFingerprintReaderTask mStartFingerprintReaderTask;
|
||||
|
||||
public static final String KEY_ALIAS = "pinKey";
|
||||
public static final String KEYSTORE = "AndroidKeyStore";
|
||||
|
|
@ -71,12 +60,7 @@ public class RequestPINActivity extends AppCompatActivity implements NfcAdapter.
|
|||
|
||||
tvPIN = findViewById(R.id.pin);
|
||||
|
||||
OnClickListener onButtonNClick = new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
tvPIN.setText(tvPIN.getText() + (String) ((Button) view).getText());
|
||||
}
|
||||
};
|
||||
OnClickListener onButtonNClick = view -> tvPIN.setText(tvPIN.getText() + (String) ((Button) view).getText());
|
||||
|
||||
Button btn0 = findViewById(R.id.btn0);
|
||||
btn0.setOnClickListener(onButtonNClick);
|
||||
|
|
@ -267,7 +251,6 @@ public class RequestPINActivity extends AppCompatActivity implements NfcAdapter.
|
|||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -328,166 +311,7 @@ public class RequestPINActivity extends AppCompatActivity implements NfcAdapter.
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public static class StartFingerprintReaderTask extends AsyncTask<Void, Void, Boolean> {
|
||||
private KeyStore keyStore;
|
||||
private Cipher cipher;
|
||||
|
||||
private FingerprintManager.CryptoObject cryptoObject;
|
||||
|
||||
FingerprintManager fingerprintManager;
|
||||
FingerprintHelper fingerprintHelper;
|
||||
|
||||
RequestPINActivity activity;
|
||||
|
||||
StartFingerprintReaderTask(RequestPINActivity activity, FingerprintManager fingerprintManager, FingerprintHelper fingerprintHelper) {
|
||||
this.fingerprintManager = fingerprintManager;
|
||||
this.fingerprintHelper = fingerprintHelper;
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
if (!getKeyStore())
|
||||
return false;
|
||||
|
||||
if (!createNewKey(false))
|
||||
return false;
|
||||
|
||||
if (!getCipher())
|
||||
return false;
|
||||
|
||||
if (!initCipher(Cipher.DECRYPT_MODE))
|
||||
return false;
|
||||
|
||||
return initCryptObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final Boolean success) {
|
||||
onCancelled();
|
||||
|
||||
if (!success) {
|
||||
doLog("Authentication failed!");
|
||||
} else {
|
||||
fingerprintHelper.startAuth(fingerprintManager, cryptoObject);
|
||||
doLog("Authenticate using fingerprint!");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled() {
|
||||
activity.mStartFingerprintReaderTask = null;
|
||||
}
|
||||
|
||||
private boolean getKeyStore() {
|
||||
doLog("Getting keystore...");
|
||||
try {
|
||||
keyStore = KeyStore.getInstance(KEYSTORE);
|
||||
keyStore.load(null); // Create empty keystore
|
||||
return true;
|
||||
} catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
public boolean createNewKey(boolean forceCreate) {
|
||||
doLog("Creating new key...");
|
||||
try {
|
||||
if (forceCreate)
|
||||
keyStore.deleteEntry(KEY_ALIAS);
|
||||
|
||||
if (!keyStore.containsAlias(KEY_ALIAS)) {
|
||||
KeyGenerator generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, KEYSTORE);
|
||||
|
||||
generator.init(new KeyGenParameterSpec.Builder(KEY_ALIAS,
|
||||
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
|
||||
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
|
||||
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
|
||||
.setUserAuthenticationRequired(true)
|
||||
.build()
|
||||
);
|
||||
|
||||
generator.generateKey();
|
||||
doLog("Key created.");
|
||||
} else
|
||||
doLog("Key exists.");
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean getCipher() {
|
||||
doLog("Getting cipher...");
|
||||
try {
|
||||
cipher = Cipher.getInstance(
|
||||
KeyProperties.KEY_ALGORITHM_AES + "/"
|
||||
+ KeyProperties.BLOCK_MODE_CBC + "/"
|
||||
+ KeyProperties.ENCRYPTION_PADDING_PKCS7);
|
||||
|
||||
return true;
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
private boolean initCipher(int mode) {
|
||||
doLog("Initializing cipher...");
|
||||
try {
|
||||
keyStore.load(null);
|
||||
SecretKey keyspec = (SecretKey) keyStore.getKey(KEY_ALIAS, null);
|
||||
|
||||
if (mode == Cipher.ENCRYPT_MODE) {
|
||||
cipher.init(mode, keyspec);
|
||||
} else {
|
||||
byte[] iv = null;
|
||||
if (activity.mode == Mode.RequestPIN || activity.mode == Mode.RequestNewPIN || activity.mode == Mode.ConfirmNewPIN) {
|
||||
iv = PINStorage.loadEncryptedIV();
|
||||
} else if (activity.mode == Mode.RequestPIN2 || activity.mode == Mode.RequestNewPIN2 || activity.mode == Mode.ConfirmNewPIN2) {
|
||||
iv = PINStorage.loadEncryptedIV2();
|
||||
}
|
||||
IvParameterSpec ivspec = new IvParameterSpec(iv);
|
||||
cipher.init(mode, keyspec, ivspec);
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (KeyPermanentlyInvalidatedException e) {
|
||||
e.printStackTrace();
|
||||
createNewKey(true); // Retry after clearing entry
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
private boolean initCryptObject() {
|
||||
doLog("Initializing crypt object...");
|
||||
try {
|
||||
cryptoObject = new FingerprintManager.CryptoObject(cipher);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static void doLog(String text) {
|
||||
public void doLog(String text) {
|
||||
// Log.e("FP", text);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import android.app.Dialog;
|
|||
import android.app.KeyguardManager;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.security.keystore.KeyGenParameterSpec;
|
||||
|
|
@ -23,6 +22,7 @@ import android.widget.CheckBox;
|
|||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.tangem.data.network.task.save_pin.ConfirmWithFingerprintTask;
|
||||
import com.tangem.domain.wallet.FingerprintHelper;
|
||||
import com.tangem.domain.wallet.PINStorage;
|
||||
import com.tangem.wallet.R;
|
||||
|
|
@ -44,17 +44,19 @@ public class SavePINActivity extends AppCompatActivity implements FingerprintHel
|
|||
private TextView tvPIN;
|
||||
private CheckBox chkUseFingerprint;
|
||||
|
||||
private ConfirmWithFingerprintTask mConfirmWithFingerprintTask;
|
||||
|
||||
public ConfirmWithFingerprintTask mConfirmWithFingerprintTask;
|
||||
|
||||
private KeyStore keyStore;
|
||||
private Cipher cipher;
|
||||
private FingerprintManager fingerprintManager;
|
||||
private FingerprintManager.CryptoObject cryptoObject;
|
||||
private FingerprintHelper fingerprintHelper;
|
||||
public FingerprintManager fingerprintManager;
|
||||
public FingerprintManager.CryptoObject cryptoObject;
|
||||
public FingerprintHelper fingerprintHelper;
|
||||
|
||||
private boolean UsePIN2 = false;
|
||||
|
||||
private enum OnConfirmAction {Save, DeleteEncryptedAndSave, Delete}
|
||||
|
||||
private OnConfirmAction onConfirmAction;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
|
@ -143,11 +145,6 @@ public class SavePINActivity extends AppCompatActivity implements FingerprintHel
|
|||
mConfirmWithFingerprintTask.cancel(true);
|
||||
}
|
||||
|
||||
|
||||
private enum OnConfirmAction {Save, DeleteEncryptedAndSave, Delete}
|
||||
|
||||
OnConfirmAction onConfirmAction;
|
||||
|
||||
private void doSavePIN() {
|
||||
if (mConfirmWithFingerprintTask != null) {
|
||||
return;
|
||||
|
|
@ -178,7 +175,7 @@ public class SavePINActivity extends AppCompatActivity implements FingerprintHel
|
|||
|
||||
onConfirmAction = OnConfirmAction.Save;
|
||||
|
||||
mConfirmWithFingerprintTask = new ConfirmWithFingerprintTask();
|
||||
mConfirmWithFingerprintTask = new ConfirmWithFingerprintTask(SavePINActivity.this);
|
||||
mConfirmWithFingerprintTask.execute((Void) null);
|
||||
} else {
|
||||
if (chkUseFingerprint.isChecked() || PINStorage.haveEncryptedPIN()) {
|
||||
|
|
@ -196,7 +193,7 @@ public class SavePINActivity extends AppCompatActivity implements FingerprintHel
|
|||
// Show a progress spinner, and kick off a background task to
|
||||
// perform the user login attempt.
|
||||
//showProgress(true);
|
||||
mConfirmWithFingerprintTask = new ConfirmWithFingerprintTask();
|
||||
mConfirmWithFingerprintTask = new ConfirmWithFingerprintTask(SavePINActivity.this);
|
||||
mConfirmWithFingerprintTask.execute((Void) null);
|
||||
} else {
|
||||
PINStorage.savePIN(tvPIN.getText().toString());
|
||||
|
|
@ -214,7 +211,7 @@ public class SavePINActivity extends AppCompatActivity implements FingerprintHel
|
|||
return;
|
||||
}
|
||||
onConfirmAction = OnConfirmAction.Delete;
|
||||
mConfirmWithFingerprintTask = new ConfirmWithFingerprintTask();
|
||||
mConfirmWithFingerprintTask = new ConfirmWithFingerprintTask(SavePINActivity.this);
|
||||
mConfirmWithFingerprintTask.execute((Void) null);
|
||||
} else {
|
||||
tvPIN.setText("");
|
||||
|
|
@ -227,7 +224,7 @@ public class SavePINActivity extends AppCompatActivity implements FingerprintHel
|
|||
return;
|
||||
}
|
||||
onConfirmAction = OnConfirmAction.Delete;
|
||||
mConfirmWithFingerprintTask = new ConfirmWithFingerprintTask();
|
||||
mConfirmWithFingerprintTask = new ConfirmWithFingerprintTask(SavePINActivity.this);
|
||||
mConfirmWithFingerprintTask.execute((Void) null);
|
||||
} else {
|
||||
tvPIN.setText("");
|
||||
|
|
@ -281,48 +278,6 @@ public class SavePINActivity extends AppCompatActivity implements FingerprintHel
|
|||
finish();
|
||||
}
|
||||
|
||||
private class ConfirmWithFingerprintTask extends AsyncTask<Void, Void, Boolean> {
|
||||
ConfirmWithFingerprintTask() {
|
||||
fingerprintHelper = new FingerprintHelper(SavePINActivity.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
if (!getKeyStore())
|
||||
return false;
|
||||
|
||||
if (!createNewKey(false))
|
||||
return false;
|
||||
|
||||
if (!getCipher())
|
||||
return false;
|
||||
|
||||
return initCipher(Cipher.ENCRYPT_MODE) && initCryptObject();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(final Boolean success) {
|
||||
onCancelled();
|
||||
|
||||
if (!success) {
|
||||
Toast.makeText(getBaseContext(), R.string.pin_save_fail, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
print("Confirm PIN action using fingerprint!");
|
||||
fingerprintHelper.startAuth(fingerprintManager, cryptoObject);
|
||||
CreateFingerPrintConfirmationDialog();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCancelled() {
|
||||
mConfirmWithFingerprintTask = null;
|
||||
if (dFingerPrintConfirmation != null) {
|
||||
dFingerPrintConfirmation.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void print(String text) {
|
||||
// Log.e("FP", text);
|
||||
}
|
||||
|
|
@ -361,7 +316,7 @@ public class SavePINActivity extends AppCompatActivity implements FingerprintHel
|
|||
return true;
|
||||
}
|
||||
|
||||
private boolean getKeyStore() {
|
||||
public boolean getKeyStore() {
|
||||
print("Getting keystore...");
|
||||
try {
|
||||
keyStore = KeyStore.getInstance(RequestPINActivity.KEYSTORE);
|
||||
|
|
@ -405,7 +360,7 @@ public class SavePINActivity extends AppCompatActivity implements FingerprintHel
|
|||
return false;
|
||||
}
|
||||
|
||||
private boolean getCipher() {
|
||||
public boolean getCipher() {
|
||||
print("Getting cipher...");
|
||||
try {
|
||||
cipher = Cipher.getInstance(
|
||||
|
|
@ -422,7 +377,7 @@ public class SavePINActivity extends AppCompatActivity implements FingerprintHel
|
|||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
private boolean initCipher(int mode) {
|
||||
public boolean initCipher(int mode) {
|
||||
print("Initializing cipher...");
|
||||
try {
|
||||
keyStore.load(null);
|
||||
|
|
@ -448,7 +403,7 @@ public class SavePINActivity extends AppCompatActivity implements FingerprintHel
|
|||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
private boolean initCryptObject() {
|
||||
public boolean initCryptObject() {
|
||||
print("Initializing crypt object...");
|
||||
try {
|
||||
cryptoObject = new FingerprintManager.CryptoObject(cipher);
|
||||
|
|
@ -459,9 +414,9 @@ public class SavePINActivity extends AppCompatActivity implements FingerprintHel
|
|||
return false;
|
||||
}
|
||||
|
||||
Dialog dFingerPrintConfirmation = null;
|
||||
public Dialog dFingerPrintConfirmation = null;
|
||||
|
||||
private void CreateFingerPrintConfirmationDialog() {
|
||||
public void CreateFingerPrintConfirmationDialog() {
|
||||
// final AlertDialogWrapper.Builder b = new AlertDialogWrapper.Builder(this);
|
||||
// switch (onConfirmAction)
|
||||
// {
|
||||
|
|
|
|||
|
|
@ -3,33 +3,24 @@ package com.tangem.presentation.activity;
|
|||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.tangem.data.network.request.ElectrumRequest;
|
||||
import com.tangem.data.network.request.InfuraRequest;
|
||||
import com.tangem.data.network.task.send_transaction.ConnectTask;
|
||||
import com.tangem.data.network.task.send_transaction.ETHRequestTask;
|
||||
import com.tangem.domain.wallet.Blockchain;
|
||||
import com.tangem.domain.wallet.CoinEngine;
|
||||
import com.tangem.domain.wallet.CoinEngineFactory;
|
||||
import com.tangem.data.network.request.ElectrumRequest;
|
||||
import com.tangem.data.network.task.ElectrumTask;
|
||||
import com.tangem.data.network.request.InfuraRequest;
|
||||
import com.tangem.data.network.task.InfuraTask;
|
||||
import com.tangem.domain.wallet.LastSignStorage;
|
||||
import com.tangem.domain.wallet.TangemCard;
|
||||
import com.tangem.wallet.R;
|
||||
import com.tangem.domain.wallet.SharedData;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
public class SendTransactionActivity extends AppCompatActivity {
|
||||
|
||||
ProgressBar progressBar;
|
||||
private TangemCard mCard;
|
||||
private ProgressBar progressBar;
|
||||
public TangemCard mCard;
|
||||
private String tx;
|
||||
|
||||
@Override
|
||||
|
|
@ -48,21 +39,20 @@ public class SendTransactionActivity extends AppCompatActivity {
|
|||
|
||||
CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain());
|
||||
if (mCard.getBlockchain() == Blockchain.Ethereum || mCard.getBlockchain() == Blockchain.EthereumTestNet || mCard.getBlockchain() == Blockchain.Token) {
|
||||
ETHRequestTask task = new ETHRequestTask(mCard.getBlockchain());
|
||||
ETHRequestTask task = new ETHRequestTask(SendTransactionActivity.this, mCard.getBlockchain());
|
||||
InfuraRequest req = InfuraRequest.SendTransaction(mCard.getWallet(), tx);
|
||||
req.setID(67);
|
||||
req.setBlockchain(mCard.getBlockchain());
|
||||
task.execute(req);
|
||||
} else if (mCard.getBlockchain() == Blockchain.Bitcoin || mCard.getBlockchain() == Blockchain.BitcoinTestNet ) {
|
||||
} else if (mCard.getBlockchain() == Blockchain.Bitcoin || mCard.getBlockchain() == Blockchain.BitcoinTestNet) {
|
||||
String nodeAddress = engine.GetNode(mCard);
|
||||
int nodePort = engine.GetNodePort(mCard);
|
||||
ConnectTask connectTask = new ConnectTask(nodeAddress, nodePort);
|
||||
ConnectTask connectTask = new ConnectTask(SendTransactionActivity.this, nodeAddress, nodePort);
|
||||
connectTask.execute(ElectrumRequest.Broadcast(mCard.getWallet(), tx));
|
||||
}
|
||||
else if (mCard.getBlockchain() == Blockchain.BitcoinCash || mCard.getBlockchain() == Blockchain.BitcoinCashTestNet ) {
|
||||
} else if (mCard.getBlockchain() == Blockchain.BitcoinCash || mCard.getBlockchain() == Blockchain.BitcoinCashTestNet) {
|
||||
String nodeAddress = engine.GetNode(mCard);
|
||||
int nodePort = engine.GetNodePort(mCard);
|
||||
ConnectTask connectTask = new ConnectTask(nodeAddress, nodePort);
|
||||
ConnectTask connectTask = new ConnectTask(SendTransactionActivity.this, nodeAddress, nodePort);
|
||||
connectTask.execute(ElectrumRequest.Broadcast(mCard.getWallet(), tx));
|
||||
}
|
||||
|
||||
|
|
@ -72,148 +62,24 @@ public class SendTransactionActivity extends AppCompatActivity {
|
|||
public boolean onKeyDown(int keycode, KeyEvent e) {
|
||||
switch (keycode) {
|
||||
case KeyEvent.KEYCODE_BACK:
|
||||
Toast.makeText(getBaseContext(),"Please wait while the payment is sent...",Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(getBaseContext(), "Please wait while the payment is sent...", Toast.LENGTH_LONG).show();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onKeyDown(keycode, e);
|
||||
}
|
||||
|
||||
void FinishWithError(String Message) {
|
||||
public void finishWithError(String Message) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra("message", "Failed to send transaction. Try again.");
|
||||
setResult(MainActivity.RESULT_CANCELED, intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
void FinishWithSuccess() {
|
||||
public void finishWithSuccess() {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra("message", "Transaction has been successfully signed and sent to blockchain node. Wallet balance will be updated in a while");
|
||||
setResult(MainActivity.RESULT_OK, intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
private class ETHRequestTask extends InfuraTask {
|
||||
ETHRequestTask(Blockchain blockchain){
|
||||
super(blockchain);
|
||||
}
|
||||
@Override
|
||||
protected void onPostExecute(List<InfuraRequest> requests) {
|
||||
super.onPostExecute(requests);
|
||||
for (InfuraRequest request : requests) {
|
||||
try {
|
||||
if (request.error == null) {
|
||||
if (request.isMethod(InfuraRequest.METHOD_ETH_SendRawTransaction)) {
|
||||
try {
|
||||
String hashTX = "";
|
||||
try {
|
||||
String tmp = request.getResultString();
|
||||
hashTX = tmp;
|
||||
}catch(JSONException e)
|
||||
{
|
||||
JSONObject msg = request.getAnswer();
|
||||
JSONObject err = msg.getJSONObject("error");
|
||||
hashTX = err.getString("message");
|
||||
LastSignStorage.setLastMessage(mCard.getWallet(), hashTX);
|
||||
FinishWithError(hashTX);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (hashTX.startsWith("0x") || hashTX.startsWith("0X")) {
|
||||
hashTX = hashTX.substring(2);
|
||||
}
|
||||
BigInteger bigInt = new BigInteger(hashTX, 16); //TODO: очень плохой способ
|
||||
LastSignStorage.setTxWasSend(mCard.getWallet());
|
||||
LastSignStorage.setLastMessage(mCard.getWallet(), "");
|
||||
BigInteger nonce = mCard.GetConfirmTXCount();
|
||||
nonce.add(BigInteger.valueOf(1));
|
||||
mCard.SetConfirmTXCount(nonce);
|
||||
Log.e("TX_RESULT", hashTX);
|
||||
FinishWithSuccess();
|
||||
}catch(Exception e)
|
||||
{
|
||||
FinishWithError(hashTX);
|
||||
}
|
||||
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
FinishWithError(e.toString());
|
||||
}
|
||||
}
|
||||
} else if (request.error != null) {
|
||||
FinishWithError(request.error);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
FinishWithError(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ConnectTask extends ElectrumTask {
|
||||
public ConnectTask(String host, int port) {
|
||||
super(host, port);
|
||||
}
|
||||
|
||||
public ConnectTask(String host, int port, SharedData sharedData) {
|
||||
super(host, port, sharedData);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Integer... values) {
|
||||
super.onProgressUpdate(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<ElectrumRequest> requests) {
|
||||
super.onPostExecute(requests);
|
||||
CoinEngine engine = CoinEngineFactory.Create(Blockchain.Bitcoin);
|
||||
|
||||
for (ElectrumRequest request : requests) {
|
||||
try {
|
||||
if (request.error == null) {
|
||||
if (request.isMethod(ElectrumRequest.METHOD_SendTransaction)) {
|
||||
try {
|
||||
String hashTX = request.getResultString();
|
||||
|
||||
try
|
||||
{
|
||||
LastSignStorage.setLastMessage(mCard.getWallet(), hashTX);
|
||||
if (hashTX.startsWith("0x") || hashTX.startsWith("0X")) {
|
||||
hashTX = hashTX.substring(2);
|
||||
}
|
||||
BigInteger bigInt = new BigInteger(hashTX, 16); //TODO: очень плохой способ
|
||||
LastSignStorage.setTxWasSend(mCard.getWallet());
|
||||
LastSignStorage.setLastMessage(mCard.getWallet(), "");
|
||||
Log.e("TX_RESULT", hashTX);
|
||||
FinishWithSuccess();
|
||||
}catch(Exception e)
|
||||
{
|
||||
engine.SwitchNode(null);
|
||||
FinishWithError(hashTX);
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
engine.SwitchNode(null);
|
||||
FinishWithError(e.toString());
|
||||
}
|
||||
}
|
||||
} else if (request.error != null) {
|
||||
engine.SwitchNode(null);
|
||||
FinishWithError(request.error);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
engine.SwitchNode(null);
|
||||
FinishWithError(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue