Updated on 2026-08-14
This commit is contained in:
parent
b690338759
commit
460a9d19c1
14 changed files with 627 additions and 29 deletions
BIN
.idea/caches/build_file_checksums.ser
generated
BIN
.idea/caches/build_file_checksums.ser
generated
Binary file not shown.
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
|
|
@ -25,7 +25,7 @@
|
|||
</value>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ dependencies {
|
|||
implementation 'org.bitcoinj:bitcoinj-core:0.14.4'
|
||||
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
|
||||
implementation 'info.hoang8f:android-segmented:1.0.6'
|
||||
implementation 'com.google.code.gson:gson:2.8.5'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,193 @@
|
|||
package com.tangem.data.network.request;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.tangem.domain.wallet.TangemCard;
|
||||
import com.tangem.util.Util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.sql.Date;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
public class VerificationServerProtocol {
|
||||
|
||||
public static class Request
|
||||
{
|
||||
public Request(CustomCommand command, Class answerClass)
|
||||
{
|
||||
this.command=command;
|
||||
this.answerClass=answerClass;
|
||||
}
|
||||
public String error;
|
||||
public CustomCommand command;
|
||||
public CustomAnswer answer;
|
||||
public Type answerClass;
|
||||
|
||||
public void doPost(String hostURL) throws IOException {
|
||||
URL url = new URL(hostURL+"/"+command.getURL());
|
||||
URLConnection con = url.openConnection();
|
||||
HttpURLConnection http = (HttpURLConnection) con;
|
||||
try {
|
||||
http.setConnectTimeout(30000);
|
||||
http.setReadTimeout(30000);
|
||||
http.setRequestMethod("POST"); // PUT is another valid option
|
||||
http.setDoOutput(true);
|
||||
|
||||
String sRequestBody = getGson().toJson(this.command);
|
||||
|
||||
byte[] out = sRequestBody.getBytes(StandardCharsets.UTF_8);
|
||||
int length = out.length;
|
||||
|
||||
http.setFixedLengthStreamingMode(length);
|
||||
http.setRequestProperty("Content-Type", "application/json");
|
||||
http.connect();
|
||||
try (OutputStream os = http.getOutputStream()) {
|
||||
os.write(out);
|
||||
}
|
||||
try (InputStream is = http.getInputStream()) {
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
|
||||
answer = getGson().fromJson(br, answerClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
http.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static abstract class CustomCommand {
|
||||
public abstract String getURL();
|
||||
|
||||
public byte[] toBytes()
|
||||
{
|
||||
return getGson().toJson(this).getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getGson().toJson(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class CustomAnswer {
|
||||
public String error;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getGson().toJson(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Verify {
|
||||
|
||||
static class RequestItem {
|
||||
public String CID;
|
||||
public String publicKey;
|
||||
}
|
||||
|
||||
static class Command extends CustomCommand {
|
||||
public RequestItem[] requests;
|
||||
|
||||
@Override
|
||||
public String getURL() {
|
||||
return "verify";
|
||||
}
|
||||
}
|
||||
|
||||
public static class ResultItem {
|
||||
public ResultItem(RequestItem request) {
|
||||
CID = request.CID;
|
||||
}
|
||||
|
||||
public String error;
|
||||
public String CID;
|
||||
public Boolean passed;
|
||||
}
|
||||
|
||||
public static class Answer extends CustomAnswer {
|
||||
public ResultItem[] results;
|
||||
}
|
||||
|
||||
public static Request prepare(TangemCard card)
|
||||
{
|
||||
Command c=new Command();
|
||||
c.requests=new RequestItem[1];
|
||||
c.requests[0]=new RequestItem();
|
||||
c.requests[0].CID=Util.bytesToHex(card.getCID());
|
||||
c.requests[0].publicKey=Util.bytesToHex(card.getCardPublicKey());
|
||||
|
||||
return new Request(c,Answer.class);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Validate {
|
||||
|
||||
static class RequestItem {
|
||||
public String CID;
|
||||
public int counter;
|
||||
public String signature;
|
||||
}
|
||||
|
||||
static class Command extends CustomCommand {
|
||||
public RequestItem[] requests;
|
||||
|
||||
@Override
|
||||
public String getURL() {
|
||||
return "validate";
|
||||
}
|
||||
}
|
||||
|
||||
static class ResultItem {
|
||||
public ResultItem(RequestItem request) {
|
||||
CID = request.CID;
|
||||
}
|
||||
public String error;
|
||||
public String CID;
|
||||
public Integer previousCounter;
|
||||
public Boolean passed;
|
||||
}
|
||||
|
||||
static class Answer extends CustomAnswer {
|
||||
public ResultItem[] results;
|
||||
}
|
||||
|
||||
public Request prepare(TangemCard card, int ValidationCounter, byte[] ValidationSignature)
|
||||
{
|
||||
Command c=new Command();
|
||||
c.requests=new RequestItem[1];
|
||||
c.requests[0].CID= Util.bytesToHex(card.getCID());
|
||||
c.requests[0].counter=ValidationCounter;
|
||||
c.requests[0].signature=Util.bytesToHex(ValidationSignature);
|
||||
return new Request(new Command(),Answer.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static Date strToDate(String date) throws ParseException {
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
|
||||
return new Date(formatter.parse(date).getTime());
|
||||
}
|
||||
|
||||
public static String dateToStr(Date date) {
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
|
||||
return formatter.format(date);
|
||||
}
|
||||
|
||||
public static Gson getGson() {
|
||||
return new GsonBuilder().create();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.tangem.data.network.task;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.tangem.data.network.request.VerificationServerProtocol;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class VerificationServerTask extends AsyncTask<VerificationServerProtocol.Request, Void, List<VerificationServerProtocol.Request>> {
|
||||
public static final String hostURL ="https://tangem-webapp.appspot.com";
|
||||
|
||||
public VerificationServerTask() {
|
||||
|
||||
}
|
||||
|
||||
protected List<VerificationServerProtocol.Request> doInBackground(VerificationServerProtocol.Request... requests) {
|
||||
List<VerificationServerProtocol.Request> result = new ArrayList<>();
|
||||
for (int i = 0; i < requests.length; i++) {
|
||||
result.add(requests[i]);
|
||||
}
|
||||
|
||||
for (VerificationServerProtocol.Request request : result) {
|
||||
try {
|
||||
request.doPost(hostURL);
|
||||
} catch (Exception e) {
|
||||
request.error = e.getMessage();
|
||||
if( request.error==null || request.error.isEmpty() )
|
||||
{
|
||||
request.error = e.getClass().getName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getValidationNodeDescription() {
|
||||
return hostURL;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ import org.json.JSONException;
|
|||
import org.json.JSONObject;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -69,20 +70,28 @@ public class UpdateWalletInfoTask extends ElectrumTask {
|
|||
String mWalletAddress = request.getParams().getString(0);
|
||||
Long confBalance = request.getResult().getLong("confirmed");
|
||||
Long unconf = request.getResult().getLong("unconfirmed");
|
||||
loadedWallet.mCard.setBalanceRecieved(true);
|
||||
|
||||
if (sharedCounter != null) {
|
||||
boolean notEqualBalance = !sharedCounter.UpdatePayload(new BigDecimal(String.valueOf(confBalance)));
|
||||
if (notEqualBalance)
|
||||
loadedWallet.mCard.setIsBalanceEqual(false);
|
||||
int counter = sharedCounter.requestCounter.incrementAndGet();
|
||||
if (counter != 1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
loadedWallet.mCard.setBalanceConfirmed(confBalance);
|
||||
loadedWallet.mCard.setBalanceUnconfirmed(unconf);
|
||||
loadedWallet.mCard.setDecimalBalance(String.valueOf(confBalance));
|
||||
|
||||
loadedWallet.mCard.setValidationNodeDescription(getValidationNodeDescription());
|
||||
} catch (JSONException e) {
|
||||
if (sharedCounter != null) {
|
||||
int errCounter = sharedCounter.errorRequest.incrementAndGet();
|
||||
loadedWallet.mCard.incFailedBalanceRequestCounter();
|
||||
if (errCounter >= sharedCounter.allRequest) {
|
||||
e.printStackTrace();
|
||||
loadedWallet.errorOnUpdate(e.toString());
|
||||
|
|
@ -270,6 +279,7 @@ public class UpdateWalletInfoTask extends ElectrumTask {
|
|||
} else {
|
||||
if (sharedCounter != null) {
|
||||
int errCounter = sharedCounter.errorRequest.incrementAndGet();
|
||||
loadedWallet.mCard.incFailedBalanceRequestCounter();
|
||||
if (errCounter >= sharedCounter.allRequest) {
|
||||
loadedWallet.errorOnUpdate(request.error);
|
||||
engine.SwitchNode(loadedWallet.mCard);
|
||||
|
|
@ -285,6 +295,7 @@ public class UpdateWalletInfoTask extends ElectrumTask {
|
|||
} catch (JSONException e) {
|
||||
if (sharedCounter != null) {
|
||||
int errCounter = sharedCounter.errorRequest.incrementAndGet();
|
||||
loadedWallet.mCard.incFailedBalanceRequestCounter();
|
||||
if (errCounter >= sharedCounter.allRequest) {
|
||||
e.printStackTrace();
|
||||
loadedWallet.errorOnUpdate(e.toString());
|
||||
|
|
|
|||
|
|
@ -610,6 +610,10 @@ public class CardProtocol {
|
|||
|
||||
mCard.setRemainingSignatures(readResult.getTagAsInt(TLV.Tag.TAG_RemainingSignatures));
|
||||
|
||||
if (readResult != null && readResult.getTLV(TLV.Tag.TAG_SignedHashes) != null) {
|
||||
mCard.setSignHashes(readResult.getTLV(TLV.Tag.TAG_SignedHashes).Value);
|
||||
}
|
||||
|
||||
} else {
|
||||
mCard.setWallet("N/A");
|
||||
}
|
||||
|
|
|
|||
163
app/src/main/java/com/tangem/domain/wallet/BalanceValidator.java
Normal file
163
app/src/main/java/com/tangem/domain/wallet/BalanceValidator.java
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
package com.tangem.domain.wallet;
|
||||
|
||||
import android.util.Pair;
|
||||
|
||||
public class BalanceValidator {
|
||||
private String firstLine;
|
||||
private String secondLine;
|
||||
private int score;
|
||||
public String GetFirstLine()
|
||||
{
|
||||
return firstLine;
|
||||
}
|
||||
public String GetSecondLine()
|
||||
{
|
||||
if(score < 0) score = 0;
|
||||
return score + "% safe. " + secondLine;
|
||||
}
|
||||
|
||||
public void Check(TangemCard card)
|
||||
{
|
||||
String defaultFirstLine = "Unknown balance.";
|
||||
String successFirstLine = "Verified balance.";
|
||||
|
||||
// rule 1
|
||||
if(!CheckOfflineBalance(card) && !CheckOnlineBalance(card)) {
|
||||
score = 0;
|
||||
secondLine = "Do not accept. Balance cannot be verified.";
|
||||
firstLine = defaultFirstLine;
|
||||
return;
|
||||
}
|
||||
// rule 2.a
|
||||
if(!VerificationWalletKey(card)) {
|
||||
score = 0;
|
||||
secondLine = "Do not accept. Wallet verification failed.";
|
||||
firstLine = defaultFirstLine;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// rule 2.c
|
||||
if(!CheckAttestationServiceResult(card)) {
|
||||
score = 0;
|
||||
secondLine = "Do not accept. Tangem Attestation service says card is not genuine.";
|
||||
firstLine = successFirstLine;
|
||||
return;
|
||||
}
|
||||
|
||||
// rule 3
|
||||
if(CheckOnlineBalance(card) && !NotConfirmTransaction(card))
|
||||
{
|
||||
if(card.isBalanceRecieved() && card.isBalanceEqual()) {
|
||||
score = 100;
|
||||
firstLine = "Verified balance.";
|
||||
secondLine += " Confirmed balance and banknote identity.";
|
||||
}
|
||||
|
||||
if(card.getFailedBalanceRequestCounter()!=0) {
|
||||
score = 100 - 10 * card.getFailedBalanceRequestCounter();
|
||||
firstLine = "Verified balance.";
|
||||
secondLine += " Not all nodes have returned balance. App is requesting more nodes to be 100% sure...";
|
||||
if(score <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
if(card.isBalanceRecieved() && !card.isBalanceEqual()) {
|
||||
score = 0;
|
||||
firstLine = "Disputed balance.";
|
||||
secondLine += " Cannot obtaine trusted balance at the moment. Try to tap and check this banknote later.";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// rule 7
|
||||
if(CheckOfflineBalance(card) && !CheckOnlineBalance(card))
|
||||
{
|
||||
score = -10;
|
||||
String firstLine = "Virified offline balance.";
|
||||
secondLine += " Restore internet connection to be more confidient.";
|
||||
if(score <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// rule 2.b
|
||||
if(!CheckAttestationServiceAvailable(card))
|
||||
{
|
||||
score = -15;
|
||||
secondLine += "Card identity was not verified. Cannot reach attestation service.";
|
||||
firstLine = successFirstLine;
|
||||
if(score <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// rule 5
|
||||
if(IsLostSecondRead(card))
|
||||
{
|
||||
score = -30;
|
||||
secondLine += " Wallet and banknote keys were not verified (tap again).";
|
||||
if(score <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// rule 4
|
||||
if(!CheckSignHashes(card))
|
||||
{
|
||||
score = -50;
|
||||
secondLine = "Unguaranteed balance.";
|
||||
firstLine += " Potential unsent transaction at the moment. Try to tap and check this banknote later.";
|
||||
if(score <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// rule 6
|
||||
if(NotConfirmTransaction(card))
|
||||
{
|
||||
score = -50;
|
||||
String firstLine = "Unguaranted balance.";
|
||||
secondLine = " Loading in progress. Wait for full confirmation in blockchain.";
|
||||
if(score <= 0)
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
boolean CheckOfflineBalance(TangemCard card)
|
||||
{
|
||||
return card.getOfflineBalance() != null;
|
||||
}
|
||||
|
||||
boolean CheckOnlineBalance(TangemCard card)
|
||||
{
|
||||
return card.isBalanceRecieved();
|
||||
}
|
||||
|
||||
boolean VerificationWalletKey(TangemCard card)
|
||||
{
|
||||
return card.isWalletPublicKeyValid();
|
||||
}
|
||||
|
||||
boolean CheckSignHashes(TangemCard card)
|
||||
{
|
||||
return card.getSignHashes()==null;
|
||||
}
|
||||
|
||||
boolean CheckAttestationServiceAvailable(TangemCard card)
|
||||
{
|
||||
return card.isOnlineVerified() != null;
|
||||
}
|
||||
|
||||
boolean CheckAttestationServiceResult(TangemCard card)
|
||||
{
|
||||
return card.isOnlineVerified() != null && card.isOnlineVerified() == true;
|
||||
}
|
||||
|
||||
boolean NotConfirmTransaction(TangemCard card)
|
||||
{
|
||||
return card.getBalanceUnconfirmed()!=0;
|
||||
}
|
||||
|
||||
boolean IsLostSecondRead(TangemCard card)
|
||||
{
|
||||
return card.isCodeConfirmed() != null;
|
||||
}
|
||||
}
|
||||
|
|
@ -117,4 +117,14 @@ public enum Issuer {
|
|||
return Issuer.Unknown;
|
||||
}
|
||||
|
||||
public static Issuer FindIssuer(String ID) {
|
||||
Issuer[] issuers = Issuer.values();
|
||||
for (int i = 1; i < issuers.length; i++) {
|
||||
if (issuers[i].ID.equals(ID)) {
|
||||
return issuers[i];
|
||||
}
|
||||
}
|
||||
return Issuer.Unknown;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.tangem.domain.wallet;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
|
|
@ -14,8 +15,32 @@ public class SharedData
|
|||
public int allRequest;
|
||||
public AtomicInteger errorRequest;
|
||||
|
||||
public BigDecimal payload;
|
||||
public synchronized boolean UpdatePayload(BigDecimal value)
|
||||
{
|
||||
|
||||
if(payload == null || payload.compareTo(value)!=0)
|
||||
{
|
||||
boolean isChange = true;
|
||||
if(payload == null)
|
||||
isChange = false;
|
||||
if(value!=BigDecimal.ZERO)
|
||||
payload = value;
|
||||
|
||||
return isChange;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SetErrorRequest(int val)
|
||||
{
|
||||
errorRequest = new AtomicInteger(val);
|
||||
}
|
||||
|
||||
public SharedData(int requstCount)
|
||||
{
|
||||
payload = BigDecimal.ZERO;
|
||||
allRequest = requstCount;
|
||||
errorRequest = new AtomicInteger(0);
|
||||
requestCounter = new AtomicInteger(0);
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ import com.tangem.wallet.R;
|
|||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Created by dvol on 16.07.2017.
|
||||
|
|
@ -270,6 +270,42 @@ public class TangemCard {
|
|||
}
|
||||
}
|
||||
|
||||
private Boolean codeConfirmed;
|
||||
public void setCodeConfirmed(Boolean codeConfirmed) {
|
||||
this.codeConfirmed = codeConfirmed;
|
||||
}
|
||||
|
||||
public Boolean isCodeConfirmed() {
|
||||
return codeConfirmed;
|
||||
}
|
||||
|
||||
private Boolean onlineVerified;
|
||||
public void setOnlineVerified(Boolean verified) {
|
||||
this.onlineVerified = verified;
|
||||
}
|
||||
|
||||
public Boolean isOnlineVerified() {
|
||||
return onlineVerified;
|
||||
}
|
||||
|
||||
private Boolean onlineValidated;
|
||||
public void setOnlineValidated(Boolean validated) {
|
||||
this.onlineValidated = validated;
|
||||
}
|
||||
|
||||
public Boolean isOnlineValidated() {
|
||||
return onlineValidated;
|
||||
}
|
||||
|
||||
private boolean balanceRecieved = false;
|
||||
public boolean isBalanceRecieved() {
|
||||
return balanceRecieved;
|
||||
}
|
||||
public void setBalanceRecieved(boolean balanceRecieved)
|
||||
{
|
||||
this.balanceRecieved = balanceRecieved;
|
||||
}
|
||||
|
||||
public int getRemainingSignatures() {
|
||||
return remainingSignatures;
|
||||
}
|
||||
|
|
@ -666,6 +702,31 @@ public class TangemCard {
|
|||
return pauseBeforePIN2;
|
||||
}
|
||||
|
||||
private AtomicInteger failedBalanceRequestCounter;
|
||||
public int incFailedBalanceRequestCounter()
|
||||
{
|
||||
if(failedBalanceRequestCounter == null)
|
||||
failedBalanceRequestCounter = new AtomicInteger(0);
|
||||
return failedBalanceRequestCounter.incrementAndGet();
|
||||
}
|
||||
public void resetFailedBalanceRequestCounter()
|
||||
{
|
||||
failedBalanceRequestCounter = new AtomicInteger(0);
|
||||
}
|
||||
public int getFailedBalanceRequestCounter()
|
||||
{
|
||||
if(failedBalanceRequestCounter == null)
|
||||
return 0;
|
||||
return failedBalanceRequestCounter.get();
|
||||
}
|
||||
|
||||
Boolean balanceEqual;
|
||||
public Boolean isBalanceEqual(){return balanceEqual;}
|
||||
public void setIsBalanceEqual(boolean isEqual)
|
||||
{
|
||||
balanceEqual = isEqual;
|
||||
}
|
||||
|
||||
private Integer settingsMask = null;
|
||||
|
||||
public void setSettingsMask(int settingsMask) {
|
||||
|
|
@ -1135,6 +1196,16 @@ public class TangemCard {
|
|||
return Denomination;
|
||||
}
|
||||
|
||||
public byte[] SignHashes;
|
||||
public void setSignHashes(byte[] SignHashes) {
|
||||
this.SignHashes = SignHashes;
|
||||
}
|
||||
|
||||
public byte[] getSignHashes() {
|
||||
return SignHashes;
|
||||
}
|
||||
|
||||
|
||||
public void clearDenomination() {
|
||||
Denomination = null;
|
||||
}
|
||||
|
|
@ -1205,12 +1276,16 @@ public class TangemCard {
|
|||
if (encryptionMode != null) B.putString("EncryptionMode", encryptionMode.name());
|
||||
if (issuer != null) B.putString("Issuer", issuer.name());
|
||||
if (firmwareVersion != null) B.putString("FirmwareVersion", firmwareVersion);
|
||||
if(balanceEqual != null) B.putBoolean("isBalanceEqual", balanceEqual);
|
||||
B.putString("BalanceDecimal", balanceDecimal);
|
||||
B.putString("BalanceDecimalAlter", balanceDecimalAlter);
|
||||
B.putBoolean("ManufacturerConfirmed", manufacturerConfirmed);
|
||||
B.putBoolean("CardPublicKeyValid", isCardPublicKeyValid());
|
||||
B.putByteArray("CardPublicKey", getCardPublicKey());
|
||||
|
||||
if(failedBalanceRequestCounter != null)
|
||||
B.putInt("FailedBalance", failedBalanceRequestCounter.get());
|
||||
if(getSignHashes()!=null) B.putByteArray("SignHashes", getSignHashes());
|
||||
B.putString("Wallet", wallet);
|
||||
B.putString("Error", error);
|
||||
B.putBoolean("WalletPublicKeyValid", isWalletPublicKeyValid());
|
||||
|
|
@ -1255,6 +1330,22 @@ public class TangemCard {
|
|||
B.putFloat("rate", rate);
|
||||
B.putFloat("rateAlter", rateAlter);
|
||||
B.putString("confirmTx", GetConfirmTXCount().toString(16));
|
||||
|
||||
if( codeConfirmed!=null )
|
||||
B.putBoolean("codeConfirmed", codeConfirmed);
|
||||
|
||||
if( codeConfirmed!=null )
|
||||
B.putBoolean("codeConfirmed", codeConfirmed);
|
||||
|
||||
if( onlineVerified!=null )
|
||||
B.putBoolean("onlineVerified", onlineVerified);
|
||||
|
||||
B.putBoolean("balanceRecieved", balanceRecieved);
|
||||
|
||||
|
||||
if( onlineValidated!=null )
|
||||
B.putBoolean("onlineValidated", onlineValidated);
|
||||
|
||||
}
|
||||
|
||||
public void LoadFromBundle(Bundle B) {
|
||||
|
|
@ -1292,12 +1383,17 @@ public class TangemCard {
|
|||
else
|
||||
encryptionMode = null;
|
||||
|
||||
if (B.containsKey("Issuer")) issuer = Issuer.valueOf(B.getString("Issuer"));
|
||||
if(B.containsKey("SignHashes")) setSignHashes(B.getByteArray("SignHashes"));
|
||||
|
||||
if(B.containsKey("FailedBalance")) failedBalanceRequestCounter = new AtomicInteger(B.getInt("FailedBalance"));
|
||||
if (B.containsKey("Issuer")) issuer = Issuer.FindIssuer(B.getString("Issuer"));
|
||||
if (B.containsKey("FirmwareVersion")) firmwareVersion = B.getString("FirmwareVersion");
|
||||
|
||||
if(B.containsKey("isBalanceEqual")) setIsBalanceEqual(B.getBoolean("isBalanceEqual"));
|
||||
cardPublicKeyValid = B.getBoolean("CardPublicKeyValid");
|
||||
if (B.containsKey("CardPublicKey")) setCardPublicKey(B.getByteArray("CardPublicKey"));
|
||||
|
||||
if(B.containsKey("balanceRecieved")) setBalanceRecieved(B.getBoolean("balanceRecieved"));
|
||||
if (B.containsKey("BalanceConfirmed")) balanceConfirmed = B.getLong("BalanceConfirmed");
|
||||
else balanceConfirmed = null;
|
||||
if (B.containsKey("BalanceUnconfirmed"))
|
||||
|
|
@ -1364,38 +1460,27 @@ public class TangemCard {
|
|||
rateAlter = B.getFloat("rateAlter");
|
||||
if (B.containsKey("confirmTx"))
|
||||
countConfirmTX = new BigInteger(B.getString("confirmTx"), 16);
|
||||
}
|
||||
|
||||
private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
|
||||
public static String bytesToHex(byte[] bytes) {
|
||||
if (bytes == null) return "";
|
||||
char[] hexChars = new char[bytes.length * 2];
|
||||
for ( int j = 0; j < bytes.length; j++ ) {
|
||||
int v = bytes[j] & 0xFF;
|
||||
hexChars[j * 2] = hexArray[v >>> 4];
|
||||
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
|
||||
}
|
||||
return new String(hexChars);
|
||||
if( B.containsKey("codeConfirmed") )
|
||||
codeConfirmed=B.getBoolean("codeConfirmed");
|
||||
|
||||
if( B.containsKey("onlineVerified") )
|
||||
onlineVerified=B.getBoolean("onlineVerified");
|
||||
|
||||
if( B.containsKey("onlineValidated") )
|
||||
onlineValidated=B.getBoolean("onlineValidated");
|
||||
}
|
||||
|
||||
public int getCardImageResource() {
|
||||
switch (getBlockchainID()) {
|
||||
case "BTC":
|
||||
if ( bytesToHex(getDenomination()).equals("40420F0000000000") )
|
||||
return R.drawable.card_btc001;
|
||||
else if (bytesToHex(getDenomination()).equals("404B4C0000000000") )
|
||||
return R.drawable.card_btc005;
|
||||
else
|
||||
return R.drawable.card_default;
|
||||
return R.drawable.card_btc001;
|
||||
|
||||
case "Token":
|
||||
if (getTokenSymbol().equals("SEED"))
|
||||
return R.drawable.card_seed;
|
||||
else
|
||||
return R.drawable.card_default;
|
||||
case "ETH\\XTZ":
|
||||
return R.drawable.card_seed;
|
||||
|
||||
default:
|
||||
return R.drawable.card_default;
|
||||
return R.drawable.card_btc001;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -272,6 +272,7 @@ public class ConfirmPaymentActivity extends AppCompatActivity implements NfcAdap
|
|||
Log.e("Build Fee error", ex.getMessage());
|
||||
}
|
||||
|
||||
mCard.resetFailedBalanceRequestCounter();
|
||||
SharedData sharedFee = new SharedData(SharedData.COUNT_REQUEST);
|
||||
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
|
|
|
|||
|
|
@ -36,12 +36,15 @@ import com.google.zxing.WriterException;
|
|||
import com.tangem.data.network.request.ElectrumRequest;
|
||||
import com.tangem.data.network.request.ExchangeRequest;
|
||||
import com.tangem.data.network.request.InfuraRequest;
|
||||
import com.tangem.data.network.request.VerificationServerProtocol;
|
||||
import com.tangem.data.network.task.VerificationServerTask;
|
||||
import com.tangem.data.network.task.loaded_wallet.ETHRequestTask;
|
||||
import com.tangem.data.network.task.loaded_wallet.RateInfoTask;
|
||||
import com.tangem.data.network.task.loaded_wallet.UpdateWalletInfoTask;
|
||||
import com.tangem.data.nfc.VerifyCardTask;
|
||||
import com.tangem.domain.cardReader.CardProtocol;
|
||||
import com.tangem.domain.cardReader.NfcManager;
|
||||
import com.tangem.domain.wallet.BalanceValidator;
|
||||
import com.tangem.domain.wallet.Blockchain;
|
||||
import com.tangem.domain.wallet.CoinEngine;
|
||||
import com.tangem.domain.wallet.CoinEngineFactory;
|
||||
|
|
@ -89,12 +92,12 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
|
|||
|
||||
public SwipeRefreshLayout mSwipeRefreshLayout;
|
||||
private RelativeLayout rlProgressBar;
|
||||
private TextView tvCardID, tvBalance, tvOffline, tvBalanceEquivalent, tvWallet, tvInputs, tvError, tvMessage, tvIssuer, tvBlockchain, tvValidationNode, tvHeader, tvCaution;
|
||||
private TextView tvCardID, tvBalance, tvBalanceLine1, tvBalanceLine2,tvOffline, tvBalanceEquivalent, tvWallet, tvInputs, tvError, tvMessage, tvIssuer, tvBlockchain, tvValidationNode, tvHeader, tvCaution;
|
||||
private ProgressBar progressBar;
|
||||
private ImageView ivBlockchain, ivPIN, ivPIN2orSecurityDelay, ivDeveloperVersion;
|
||||
private AppCompatButton btnExtract;
|
||||
|
||||
public List<UpdateWalletInfoTask> updateTasks = new ArrayList<>();
|
||||
public List<AsyncTask> updateTasks = new ArrayList<>();
|
||||
private boolean lastReadSuccess = true;
|
||||
private VerifyCardTask verifyCardTask = null;
|
||||
private int requestPIN2Count = 0;
|
||||
|
|
@ -102,11 +105,48 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
|
|||
private String newPIN = "", newPIN2 = "";
|
||||
private CardProtocol mCardProtocol;
|
||||
private int scanTimes = 0;
|
||||
OnlineVerifyTask onlineVerifyTask;
|
||||
|
||||
public LoadedWallet() {
|
||||
|
||||
}
|
||||
|
||||
private class OnlineVerifyTask extends VerificationServerTask {
|
||||
|
||||
@Override
|
||||
protected void onCancelled() {
|
||||
super.onCancelled();
|
||||
updateTasks.remove(this);
|
||||
onlineVerifyTask=null;
|
||||
if (updateTasks.size() == 0) mSwipeRefreshLayout.setRefreshing(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<VerificationServerProtocol.Request> requests) {
|
||||
super.onPostExecute(requests);
|
||||
Log.i("OnlineVerifyTask", "onPostExecute[" + String.valueOf(updateTasks.size()) + "]");
|
||||
updateTasks.remove(this);
|
||||
onlineVerifyTask=null;
|
||||
|
||||
for (VerificationServerProtocol.Request request : requests) {
|
||||
if (request.error == null) {
|
||||
VerificationServerProtocol.Verify.Answer answer = (VerificationServerProtocol.Verify.Answer) request.answer;
|
||||
if (answer.error == null) {
|
||||
mCard.setOnlineVerified(answer.results[0].passed);
|
||||
} else {
|
||||
mCard.setOnlineVerified(null);
|
||||
errorOnUpdate(request.error);
|
||||
}
|
||||
} else {
|
||||
mCard.setOnlineVerified(null);
|
||||
errorOnUpdate(request.error);
|
||||
}
|
||||
}
|
||||
if (updateTasks.size() == 0) mSwipeRefreshLayout.setRefreshing(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
|
@ -127,6 +167,8 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
|
|||
rlProgressBar = v.findViewById(R.id.rlProgressBar);
|
||||
ImageView ivTangemCard = v.findViewById(R.id.ivTangemCard);
|
||||
tvBalance = v.findViewById(R.id.tvBalance);
|
||||
tvBalanceLine1 = v.findViewById(R.id.tvBalanceLine1);
|
||||
tvBalanceLine2 = v.findViewById(R.id.tvBalanceLine2);
|
||||
tvOffline = v.findViewById(R.id.tvOffline);
|
||||
tvCardID = v.findViewById(R.id.tvCardID);
|
||||
tvWallet = v.findViewById(R.id.tvWallet);
|
||||
|
|
@ -177,6 +219,12 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
|
|||
mSwipeRefreshLayout.postDelayed(this::onRefresh, 1000);
|
||||
}
|
||||
|
||||
if ( (mCard.isOnlineVerified()==null || !mCard.isOnlineVerified()) && onlineVerifyTask ==null) {
|
||||
onlineVerifyTask = new OnlineVerifyTask();
|
||||
updateTasks.add(onlineVerifyTask);
|
||||
onlineVerifyTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, VerificationServerProtocol.Verify.prepare(mCard));
|
||||
}
|
||||
|
||||
startVerify(lastTag);
|
||||
|
||||
tvWallet.setText(mCard.getWallet());
|
||||
|
|
@ -266,7 +314,7 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
|
|||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
for (UpdateWalletInfoTask ut : updateTasks) {
|
||||
for (AsyncTask ut : updateTasks) {
|
||||
ut.cancel(true);
|
||||
}
|
||||
mNfcManager.onStop();
|
||||
|
|
@ -465,7 +513,9 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
|
|||
CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain());
|
||||
|
||||
if (mCard.getBlockchain() == Blockchain.Bitcoin || mCard.getBlockchain() == Blockchain.BitcoinTestNet) {
|
||||
mCard.resetFailedBalanceRequestCounter();
|
||||
SharedData data = new SharedData(SharedData.COUNT_REQUEST);
|
||||
mCard.resetFailedBalanceRequestCounter();
|
||||
for (int i = 0; i < data.allRequest; ++i) {
|
||||
String nodeAddress = Objects.requireNonNull(engine).GetNextNode(mCard);
|
||||
int nodePort = engine.GetNextNodePort(mCard);
|
||||
|
|
@ -483,6 +533,7 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
|
|||
|
||||
|
||||
} else if (mCard.getBlockchain() == Blockchain.BitcoinCash || mCard.getBlockchain() == Blockchain.BitcoinCashTestNet) {
|
||||
mCard.resetFailedBalanceRequestCounter();
|
||||
SharedData data = new SharedData(SharedData.COUNT_REQUEST);
|
||||
for (int i = 0; i < data.allRequest; ++i) {
|
||||
String nodeAddress = Objects.requireNonNull(engine).GetNextNode(mCard);
|
||||
|
|
@ -689,6 +740,14 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
|
|||
|
||||
CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain());
|
||||
|
||||
if (mCard.getBlockchain() == Blockchain.Bitcoin || mCard.getBlockchain() == Blockchain.BitcoinTestNet) {
|
||||
|
||||
BalanceValidator validator = new BalanceValidator();
|
||||
validator.Check(mCard);
|
||||
tvBalanceLine1.setText(validator.GetFirstLine());
|
||||
tvBalanceLine2.setText(validator.GetSecondLine());
|
||||
}
|
||||
|
||||
if (engine.HasBalanceInfo(mCard) || mCard.getOfflineBalance() == null) {
|
||||
if (mCard.getBlockchain() == Blockchain.Token) {
|
||||
Spanned html = Html.fromHtml(engine.GetBalanceWithAlter(mCard));
|
||||
|
|
|
|||
|
|
@ -431,6 +431,7 @@ public class Main extends Fragment implements NfcAdapter.ReaderCallback, CardLis
|
|||
taskRate.execute(rate);
|
||||
|
||||
} else if (card.getBlockchain() == Blockchain.BitcoinTestNet || card.getBlockchain() == Blockchain.Bitcoin) {
|
||||
card.resetFailedBalanceRequestCounter();
|
||||
SharedData data = new SharedData(SharedData.COUNT_REQUEST);
|
||||
for (int i = 0; i < data.allRequest; ++i) {
|
||||
|
||||
|
|
@ -445,6 +446,7 @@ public class Main extends Fragment implements NfcAdapter.ReaderCallback, CardLis
|
|||
}
|
||||
|
||||
} else if (card.getBlockchain() == Blockchain.BitcoinCashTestNet || card.getBlockchain() == Blockchain.BitcoinCash) {
|
||||
card.resetFailedBalanceRequestCounter();
|
||||
SharedData data = new SharedData(SharedData.COUNT_REQUEST);
|
||||
for (int i = 0; i < data.allRequest; ++i) {
|
||||
|
||||
|
|
@ -515,6 +517,7 @@ public class Main extends Fragment implements NfcAdapter.ReaderCallback, CardLis
|
|||
taskRate.execute(rate);
|
||||
|
||||
} else if (card.getBlockchain() == Blockchain.BitcoinTestNet || card.getBlockchain() == Blockchain.Bitcoin) {
|
||||
card.resetFailedBalanceRequestCounter();
|
||||
SharedData data = new SharedData(SharedData.COUNT_REQUEST);
|
||||
|
||||
for (int i = 0; i < data.allRequest; ++i) {
|
||||
|
|
@ -538,6 +541,7 @@ public class Main extends Fragment implements NfcAdapter.ReaderCallback, CardLis
|
|||
taskRate.execute(rate);
|
||||
|
||||
} else if (card.getBlockchain() == Blockchain.BitcoinCashTestNet || card.getBlockchain() == Blockchain.BitcoinCash) {
|
||||
card.resetFailedBalanceRequestCounter();
|
||||
SharedData data = new SharedData(SharedData.COUNT_REQUEST);
|
||||
|
||||
for (int i = 0; i < data.allRequest; ++i) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue