Updated on 2026-08-14

This commit is contained in:
Tangem 2018-12-10 12:05:32 +03:00
parent d4e76c4a00
commit 7737b890bb
124 changed files with 1067 additions and 706 deletions

4
.idea/gradle.xml generated
View file

@ -9,7 +9,9 @@
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/tangemcard" />
<option value="$PROJECT_DIR$/tangemcard-android" />
<option value="$PROJECT_DIR$/tangemcard-common" />
<option value="$PROJECT_DIR$/tangemserver-android" />
</set>
</option>
<option name="resolveModulePerSourceSet" value="false" />

View file

@ -44,7 +44,9 @@ android {
}
dependencies {
implementation project(':tangemcard')
implementation project(':tangemcard-common')
implementation project(':tangemcard-android')
implementation project(':tangemserver-android')
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support:support-compat:28.0.0'

View file

@ -8,6 +8,7 @@
android:required="true" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.INTERNET" />

View file

@ -3,13 +3,25 @@ package com.tangem;
import android.app.Application;
import android.support.v7.app.AppCompatDelegate;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.tangem.tangemserver.android.data.LocalStorage;
import com.tangem.di.DaggerNavigatorComponent;
import com.tangem.di.DaggerNetworkComponent;
import com.tangem.di.NavigatorComponent;
import com.tangem.di.NetworkComponent;
import com.tangem.tangemcard.data.Issuer;
import com.tangem.tangemcard.data.local.Firmwares;
import com.tangem.tangemcard.data.local.PINStorage;
import com.tangem.tangemcard.android.data.Firmwares;
import com.tangem.tangemcard.android.data.PINStorage;
import com.tangem.tangemcard.data.external.FirmwaresDigestsProvider;
import com.tangem.tangemcard.data.external.PINsProvider;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.List;
public class App extends Application {
@ -33,6 +45,10 @@ public class App extends Application {
return navigatorComponent;
}
public static LocalStorage localStorage;
public static PINsProvider pinStorage;
public static FirmwaresDigestsProvider firmwaresStorage;
@Override
public void onCreate() {
super.onCreate();
@ -46,11 +62,13 @@ public class App extends Application {
if (PINStorage.needInit())
PINStorage.init(getApplicationContext());
if (Issuer.needInit())
Issuer.init(getApplicationContext());
initIssuers();
if (Firmwares.needInit())
Firmwares.init(getApplicationContext());
firmwaresStorage=new Firmwares(getApplicationContext());
localStorage=new LocalStorage(getApplicationContext());
pinStorage=new PINStorage();
}
/**
@ -69,4 +87,21 @@ public class App extends Application {
.build();
}
public void initIssuers() {
try {
try (InputStream is = getApplicationContext().getAssets().open("issuers.json")) {
try (InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
Type listType = new TypeToken<List<Issuer>>() {
}.getType();
Issuer.fillIssuers(new Gson().fromJson(reader, listType));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View file

@ -1,4 +1,4 @@
package com.tangem.tangemcard.data;
package com.tangem.data;
import com.tangem.tangemcard.R;

View file

@ -8,7 +8,7 @@ import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import com.tangem.tangemcard.data.local.PINStorage;
import com.tangem.tangemcard.android.data.PINStorage;
import com.tangem.presentation.activity.PinRequestActivity;
import java.io.IOException;

View file

@ -5,16 +5,7 @@ import android.support.annotation.NonNull;
import android.util.Log;
import com.tangem.App;
import com.tangem.tangemcard.data.network.TangemApi;
import com.tangem.tangemcard.data.network.model.CardVerifyAndGetInfo;
import com.tangem.data.network.model.RateInfoResponse;
import com.tangem.tangemcard.data.TangemCard;
import com.tangem.tangemcard.util.Util;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;

View file

@ -3,8 +3,8 @@ package com.tangem.data.network;
import android.util.Log;
import com.tangem.App;
import com.tangem.tangemcard.data.Blockchain;
import com.tangem.tangemcard.data.TangemCard;
import com.tangem.domain.wallet.TangemContext;
import com.tangem.data.Blockchain;
import com.tangem.domain.wallet.bch.BitcoinCashNode;
import com.tangem.domain.wallet.btc.BitcoinNode;
import com.tangem.domain.wallet.btc.BitcoinNodeTestNet;
@ -62,9 +62,9 @@ public class ServerApiElectrum {
electrumRequestDataListener = listener;
}
public void electrumRequestData(TangemCard card, ElectrumRequest electrumRequest) {
public void electrumRequestData(TangemContext ctx, ElectrumRequest electrumRequest) {
Observable<ElectrumRequest> checkElectrumDataObserver = Observable.just(electrumRequest)
.doOnNext(electrumRequest1 -> doElectrumRequest(card, electrumRequest))
.doOnNext(electrumRequest1 -> doElectrumRequest(ctx, electrumRequest))
.flatMap(electrumRequest1 -> {
if (electrumRequest1.answerData == null) {
@ -106,11 +106,11 @@ public class ServerApiElectrum {
});
}
private List<ElectrumRequest> doElectrumRequest(TangemCard card, ElectrumRequest electrumRequest) {
private List<ElectrumRequest> doElectrumRequest(TangemContext ctx, ElectrumRequest electrumRequest) {
String host;
int port;
String proto;
if (card.getBlockchain() == Blockchain.BitcoinTestNet) {
if (ctx.getBlockchain() == Blockchain.BitcoinTestNet) {
BitcoinNodeTestNet bitcoinNodeTestNet = BitcoinNodeTestNet.values()[new Random().nextInt(BitcoinNodeTestNet.values().length)];
host = bitcoinNodeTestNet.getHost();
port = bitcoinNodeTestNet.getPort();
@ -120,7 +120,7 @@ public class ServerApiElectrum {
return doElectrumRequestTcp(electrumRequest, host, port);
} else if (card.getBlockchain() == Blockchain.BitcoinCash) {
} else if (ctx.getBlockchain() == Blockchain.BitcoinCash) {
BitcoinCashNode bitcoinCashNode = BitcoinCashNode.values()[new Random().nextInt(BitcoinCashNode.values().length)];
host = bitcoinCashNode.getHost();
port = bitcoinCashNode.getPort();
@ -135,7 +135,7 @@ public class ServerApiElectrum {
return doElectrumRequestSsl(electrumRequest, host, port);
}
} else if (card.getBlockchain() == Blockchain.Bitcoin) {
} else if (ctx.getBlockchain() == Blockchain.Bitcoin) {
BitcoinNode bitcoinNode = BitcoinNode.values()[new Random().nextInt(BitcoinNode.values().length)];
host = bitcoinNode.getHost();
port = bitcoinNode.getPort();

View file

@ -2,16 +2,12 @@ package com.tangem.di
import android.app.Activity
import android.nfc.Tag
import android.os.Bundle
import com.tangem.Constant
import com.tangem.domain.wallet.CoinData
import com.tangem.domain.wallet.TangemContext
import com.tangem.presentation.activity.EmptyWalletActivity
import com.tangem.presentation.activity.LoadedWalletActivity
import com.tangem.presentation.activity.MainActivity
import com.tangem.presentation.activity.VerifyCardActivity
import com.tangem.presentation.fragment.LoadedWallet
import com.tangem.tangemcard.data.TangemCard
import com.tangem.presentation.activity.*
class Navigator {

View file

@ -3,7 +3,7 @@ package com.tangem.domain.wallet;
import android.os.Bundle;
import android.util.Log;
import com.tangem.tangemcard.data.Blockchain;
import com.tangem.data.Blockchain;
import java.util.concurrent.atomic.AtomicInteger;

View file

@ -3,12 +3,10 @@ package com.tangem.domain.wallet;
import android.net.Uri;
import android.text.InputFilter;
import com.tangem.tangemcard.data.Blockchain;
import com.tangem.data.Blockchain;
import com.tangem.tangemcard.reader.CardProtocol;
import com.tangem.tangemcard.tasks.SignTask;
import org.jetbrains.annotations.Nullable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;

View file

@ -6,7 +6,7 @@ import com.tangem.domain.wallet.btc.BtcEngine
import com.tangem.domain.wallet.eth.EthEngine
import com.tangem.domain.wallet.token.TokenEngine
import com.tangem.domain.wallet.bch.BtcCashEngine
import com.tangem.tangemcard.data.Blockchain
import com.tangem.data.Blockchain
/**
* Factory for create specific engine

View file

@ -5,8 +5,9 @@ import android.content.Intent;
import android.os.Bundle;
import com.tangem.Constant;
import com.tangem.tangemcard.data.Blockchain;
import com.tangem.data.Blockchain;
import com.tangem.tangemcard.data.TangemCard;
import com.tangem.tangemcard.data.TangemCardExtensionsKt;
public class TangemContext {
@ -17,7 +18,6 @@ public class TangemContext {
private String error;
private String message;
public TangemContext() {
}
@ -28,12 +28,29 @@ public class TangemContext {
public Blockchain getBlockchain() {
if (card == null) return Blockchain.Unknown;
return card.getBlockchain();
Blockchain blockchain=Blockchain.fromId(card.getBlockchainID());
if( (blockchain==Blockchain.Ethereum || blockchain==Blockchain.EthereumTestNet)&& card.isToken() )
{
return Blockchain.Token;
}
return blockchain;
}
public void setBlockchain(Blockchain blockchain) {
if (card == null) return;
card.setBlockchain(blockchain);
// public void setBlockchain(Blockchain blockchain) {
// if (card == null) return;
// card.setBlockchainID(blockchain.getID());
// }
// private String blockchainName = "";
public String getBlockchainName() {
Blockchain blockchain=getBlockchain();
if( (blockchain==Blockchain.Ethereum || blockchain==Blockchain.EthereumTestNet)&& card.isToken() ) {
String token = card.getTokenSymbol();
return token + " <br><small><small> " + getBlockchain().getOfficialName() + " ERC20 token</small></small>";
}else {
return blockchain.getOfficialName();
}
}
public Context getContext() {
@ -85,9 +102,9 @@ public class TangemContext {
TangemContext tangemContext = new TangemContext();
tangemContext.setContext(context);
if (bundle.containsKey(TangemCard.EXTRA_UID)) {
tangemContext.card = new TangemCard(bundle.getString(TangemCard.EXTRA_UID));
tangemContext.card.loadFromBundle(bundle.getBundle(TangemCard.EXTRA_CARD));
if (bundle.containsKey(TangemCardExtensionsKt.EXTRA_TANGEM_CARD_UID)) {
tangemContext.card = new TangemCard(bundle.getString(TangemCardExtensionsKt.EXTRA_TANGEM_CARD_UID));
TangemCardExtensionsKt.loadFromBundle(tangemContext.card, bundle.getBundle(TangemCardExtensionsKt.EXTRA_TANGEM_CARD));
}
if (tangemContext.getBlockchain() != null) {
@ -106,8 +123,8 @@ public class TangemContext {
public void saveToIntent(Intent intent) {
if (card != null) {
intent.putExtra(TangemCard.EXTRA_UID, card.getUID());
intent.putExtra(TangemCard.EXTRA_CARD, card.getAsBundle());
intent.putExtra(TangemCardExtensionsKt.EXTRA_TANGEM_CARD_UID, card.getUID());
intent.putExtra(TangemCardExtensionsKt.EXTRA_TANGEM_CARD, TangemCardExtensionsKt.getAsBundle(card));
}
if (coinData != null) {

View file

@ -4,12 +4,9 @@ import android.net.Uri;
import android.text.InputFilter;
import com.tangem.domain.wallet.BCHUtils;
import com.tangem.tangemcard.data.local.PINStorage;
import com.tangem.tangemcard.reader.CardProtocol;
import com.tangem.tangemcard.reader.TLV;
import com.tangem.domain.wallet.BalanceValidator;
import com.tangem.tangemcard.data.Blockchain;
import com.tangem.domain.wallet.CoinEngineFactory;
import com.tangem.data.Blockchain;
import com.tangem.domain.wallet.btc.BtcData;
import com.tangem.domain.wallet.CoinData;
import com.tangem.domain.wallet.CoinEngine;

View file

@ -3,12 +3,10 @@ package com.tangem.domain.wallet.btc;
import android.net.Uri;
import android.text.InputFilter;
import com.tangem.tangemcard.data.local.PINStorage;
import com.tangem.tangemcard.reader.CardProtocol;
import com.tangem.tangemcard.reader.TLV;
import com.tangem.domain.wallet.BalanceValidator;
import com.tangem.domain.wallet.Base58;
import com.tangem.tangemcard.data.Blockchain;
import com.tangem.data.Blockchain;
import com.tangem.domain.wallet.CoinData;
import com.tangem.domain.wallet.CoinEngine;
import com.tangem.tangemcard.data.TangemCard;

View file

@ -4,16 +4,12 @@ import android.net.Uri;
import android.text.InputFilter;
import android.util.Log;
import com.tangem.tangemcard.data.local.PINStorage;
import com.tangem.tangemcard.reader.CardProtocol;
import com.tangem.tangemcard.reader.TLV;
import com.tangem.domain.wallet.BalanceValidator;
import com.tangem.tangemcard.data.Blockchain;
import com.tangem.data.Blockchain;
import com.tangem.domain.wallet.CoinData;
import com.tangem.domain.wallet.CoinEngine;
import com.tangem.domain.wallet.ECDSASignatureETH;
import com.tangem.domain.wallet.EthTransaction;
import com.tangem.tangemcard.data.Issuer;
import com.tangem.domain.wallet.Keccak256;
import com.tangem.tangemcard.data.TangemCard;
import com.tangem.domain.wallet.TangemContext;
@ -236,7 +232,7 @@ public class EthEngine extends CoinEngine {
@Override
public Uri getShareWalletUriExplorer() {
if (ctx.getCard().getBlockchain() == Blockchain.EthereumTestNet)
if (ctx.getBlockchain() == Blockchain.EthereumTestNet)
return Uri.parse("https://rinkeby.etherscan.io/address/" + ctx.getCoinData().getWallet());
else
return Uri.parse("https://etherscan.io/address/" + ctx.getCoinData().getWallet());

View file

@ -5,16 +5,11 @@ import android.text.InputFilter;
import android.util.Log;
import com.google.common.base.Strings;
import com.tangem.tangemcard.data.Blockchain;
import com.tangem.tangemcard.data.local.PINStorage;
import com.tangem.tangemcard.reader.CardProtocol;
import com.tangem.tangemcard.reader.TLV;
import com.tangem.domain.wallet.BalanceValidator;
import com.tangem.domain.wallet.CoinData;
import com.tangem.domain.wallet.CoinEngine;
import com.tangem.domain.wallet.ECDSASignatureETH;
import com.tangem.domain.wallet.EthTransaction;
import com.tangem.tangemcard.data.Issuer;
import com.tangem.domain.wallet.Keccak256;
import com.tangem.tangemcard.data.TangemCard;
import com.tangem.domain.wallet.TangemContext;

View file

@ -18,11 +18,12 @@ import com.tangem.data.network.ServerApiCommon
import com.tangem.data.network.ServerApiElectrum
import com.tangem.data.network.ServerApiInfura
import com.tangem.data.network.model.InfuraResponse
import com.tangem.tangemcard.reader.NfcManager
import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.domain.wallet.*
import com.tangem.domain.wallet.btc.BtcData
import com.tangem.tangemcard.data.Blockchain
import com.tangem.data.Blockchain
import com.tangem.tangemcard.data.TangemCard
import com.tangem.tangemcard.data.loadFromBundle
import com.tangem.tangemcard.util.Util
import com.tangem.util.*
import com.tangem.wallet.R
@ -456,9 +457,9 @@ class ConfirmPaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
return realTX.size
}
private fun requestElectrum(card: TangemCard, electrumRequest: ElectrumRequest) {
private fun requestElectrum(ctx: TangemContext, electrumRequest: ElectrumRequest) {
if (UtilHelper.isOnline(this)) {
serverApiElectrum.electrumRequestData(card, electrumRequest)
serverApiElectrum.electrumRequestData(ctx, electrumRequest)
} else
finishWithError(Activity.RESULT_CANCELED, getString(R.string.cannot_obtain_data_from_blockchain))
}

View file

@ -12,13 +12,16 @@ import android.support.v7.app.AppCompatActivity
import android.view.View
import android.widget.ProgressBar
import android.widget.Toast
import com.tangem.App
import com.tangem.tangemcard.tasks.CreateNewWalletTask
import com.tangem.tangemcard.reader.CardProtocol
import com.tangem.tangemcard.reader.NfcManager
import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.domain.wallet.TangemContext
import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog
import com.tangem.presentation.dialog.WaitSecurityDelayDialog
import com.tangem.tangemcard.android.reader.NfcReader
import com.tangem.tangemcard.util.Util
import com.tangem.tangemcard.data.asBundle
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_create_new_wallet.*
@ -31,7 +34,7 @@ class CreateNewWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback,
}
private lateinit var ctx: TangemContext
private var nfcManager: NfcManager? = null
private lateinit var nfcManager: NfcManager
private var createNewWalletTask: CreateNewWalletTask? = null
private var lastReadSuccess = true
@ -70,7 +73,7 @@ class CreateNewWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback,
} else {
isoDep.timeout = ctx.card!!.pauseBeforePIN2 + 65000
}
createNewWalletTask = CreateNewWalletTask(this, ctx.card, nfcManager, isoDep, this)
createNewWalletTask = CreateNewWalletTask(ctx.card, NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage,this)
createNewWalletTask!!.start()
} else {
// Log.d(TAG, "Mismatch card UID (" + sUID + " instead of " + mCard.getUID() + ")");
@ -137,7 +140,7 @@ class CreateNewWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback,
val intent = Intent()
intent.putExtra("message", "Cannot create wallet. Make sure you enter correct PIN2!")
intent.putExtra("UID", cardProtocol.card.uid)
intent.putExtra("Card", cardProtocol.card.asBundle)
intent.putExtra("Card", cardProtocol.card!!.asBundle)
setResult(RESULT_INVALID_PIN, intent)
finish()
} catch (e: Exception) {

View file

@ -13,13 +13,18 @@ import android.support.v7.app.AppCompatActivity
import android.text.Html
import android.view.View
import android.widget.Toast
import com.tangem.App
import com.tangem.di.Navigator
import com.tangem.tangemcard.tasks.VerifyCardTask
import com.tangem.tangemcard.reader.CardProtocol
import com.tangem.tangemcard.reader.NfcManager
import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.tangemcard.data.TangemCard
import com.tangem.domain.wallet.TangemContext
import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog
import com.tangem.presentation.dialog.WaitSecurityDelayDialog
import com.tangem.tangemcard.android.reader.NfcReader
import com.tangem.tangemcard.data.asBundle
import com.tangem.tangemcard.data.loadFromBundle
import com.tangem.tangemcard.util.Util
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_empty_wallet.*
@ -40,7 +45,7 @@ class EmptyWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
}
}
private var nfcManager: NfcManager? = null
private lateinit var nfcManager: NfcManager
private lateinit var ctx: TangemContext
private var lastReadSuccess = true
private var verifyCardTask: VerifyCardTask? = null
@ -59,15 +64,15 @@ class EmptyWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
tvIssuer.text = ctx.card!!.issuerDescription
//tvBlockchain.text = ctx.card!!.blockchainName
if (ctx.card!!.tokenSymbol.length > 1) {
val html = Html.fromHtml(ctx.card!!.blockchainName)
val html = Html.fromHtml(ctx.blockchainName)
tvBlockchain.text = html
} else
tvBlockchain.text = ctx.card!!.blockchainName
tvBlockchain.text = ctx.blockchainName
tvCardID.text = ctx.card!!.cidDescription
imgBlockchain.setImageResource(ctx.card!!.blockchain.getImageResource(this, ctx.card!!.tokenSymbol))
imgBlockchain.setImageResource(ctx.blockchain.getImageResource(this, ctx.card!!.tokenSymbol))
if (ctx.card!!.useDefaultPIN1()!!) {
if (ctx.card!!.useDefaultPIN1()) {
imgPIN.setImageResource(R.drawable.unlock_pin1)
imgPIN.setOnClickListener { Toast.makeText(this@EmptyWalletActivity, R.string.this_banknote_protected_default_PIN1_code, Toast.LENGTH_LONG).show() }
} else {
@ -175,7 +180,7 @@ class EmptyWalletActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
isoDep.timeout = 65000
}
//lastTag = tag;
verifyCardTask = VerifyCardTask(this, ctx.card, nfcManager, isoDep, this)
verifyCardTask = VerifyCardTask(ctx.card, NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, App.firmwaresStorage, this)
verifyCardTask!!.start()
} catch (e: Exception) {
e.printStackTrace()

View file

@ -27,21 +27,21 @@ import com.scottyab.rootbeer.RootBeer
import com.tangem.App
import com.tangem.Constant
import com.tangem.data.Logger
import com.tangem.tangemcard.data.local.PINStorage
import com.tangem.data.network.ServerApiCommon
import com.tangem.tangemcard.data.nfc.DeviceNFCAntennaLocation
import com.tangem.tangemcard.android.nfc.DeviceNFCAntennaLocation
import com.tangem.tangemcard.tasks.ReadCardInfoTask
import com.tangem.di.Navigator
import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemContext
import com.tangem.tangemcard.reader.CardProtocol
import com.tangem.tangemcard.data.local.Firmwares
import com.tangem.tangemcard.reader.NfcManager
import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog
import com.tangem.presentation.dialog.RootFoundDialog
import com.tangem.presentation.dialog.WaitSecurityDelayDialog
import com.tangem.tangemcard.data.Issuer
import com.tangem.tangemcard.android.reader.NfcReader
import com.tangem.tangemcard.data.TangemCard
import com.tangem.tangemcard.data.loadFromBundle
import com.tangem.tangemcard.data.saveToBundle
import com.tangem.util.CommonUtil
import com.tangem.util.PhoneUtility
import com.tangem.wallet.BuildConfig
@ -70,7 +70,7 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
// }
}
private var nfcManager: NfcManager? = null
private lateinit var nfcManager: NfcManager
private var zipFile: File? = null
private var antenna: DeviceNFCAntennaLocation? = null
private var unsuccessReadCount = 0
@ -264,7 +264,7 @@ class MainActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoco
}
lastTag = tag
readCardInfoTask = ReadCardInfoTask(this, nfcManager, isoDep, this)
readCardInfoTask = ReadCardInfoTask(NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, this)
readCardInfoTask!!.start()
// Log.i(TAG, "onTagDiscovered " + Arrays.toString(tag.getId()));

View file

@ -21,10 +21,13 @@ import android.view.View
import android.widget.Button
import com.tangem.Constant
import com.tangem.data.fingerprint.StartFingerprintReaderTask
import com.tangem.tangemcard.reader.NfcManager
import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.data.fingerprint.FingerprintHelper
import com.tangem.tangemcard.data.local.PINStorage
import com.tangem.tangemcard.android.data.PINStorage
import com.tangem.tangemcard.data.TangemCard
import com.tangem.tangemcard.data.loadFromBundle
import com.tangem.tangemcard.data.EXTRA_TANGEM_CARD
import com.tangem.tangemcard.data.EXTRA_TANGEM_CARD_UID
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_pin_request.*
import kotlinx.android.synthetic.main.layout_pin_buttons.*
@ -89,9 +92,9 @@ class PinRequestActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Finge
else if (mode == Mode.ConfirmNewPIN2)
tvPinPrompt.setText(R.string.confirm_new_pin_2)
else if (mode == Mode.RequestPIN2) {
val uid = intent.getStringExtra(TangemCard.EXTRA_UID)
val uid = intent.getStringExtra(EXTRA_TANGEM_CARD_UID)
val card = TangemCard(uid)
card.loadFromBundle(intent.getBundleExtra(TangemCard.EXTRA_CARD))
card.loadFromBundle(intent.getBundleExtra(EXTRA_TANGEM_CARD))
if (card.PIN2 == TangemCard.PIN2_Mode.DefaultPIN2 || card.PIN2 == TangemCard.PIN2_Mode.Unchecked) {
// if we know PIN2 or not try default previously - use it

View file

@ -23,7 +23,7 @@ import android.widget.Toast
import com.tangem.Constant
import com.tangem.data.fingerprint.ConfirmWithFingerprintTask
import com.tangem.data.fingerprint.FingerprintHelper
import com.tangem.tangemcard.data.local.PINStorage
import com.tangem.tangemcard.android.data.PINStorage
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_pin_save.*
import kotlinx.android.synthetic.main.layout_pin_buttons.*

View file

@ -13,13 +13,15 @@ import android.support.v7.app.AppCompatActivity
import android.view.View
import android.widget.ProgressBar
import android.widget.Toast
import com.tangem.App
import com.tangem.Constant
import com.tangem.tangemcard.tasks.SwapPINTask
import com.tangem.tangemcard.reader.CardProtocol
import com.tangem.tangemcard.reader.NfcManager
import com.tangem.tangemcard.data.TangemCard
import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog
import com.tangem.presentation.dialog.WaitSecurityDelayDialog
import com.tangem.tangemcard.android.reader.NfcReader
import com.tangem.tangemcard.data.*
import com.tangem.tangemcard.util.Util
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_pin_swap.*
@ -39,7 +41,7 @@ class PinSwapActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProt
const val RESULT_INVALID_PIN = Activity.RESULT_FIRST_USER
}
private var nfcManager: NfcManager? = null
private lateinit var nfcManager: NfcManager
private var card: TangemCard? = null
private var newPIN: String? = null
@ -57,8 +59,8 @@ class PinSwapActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProt
nfcManager = NfcManager(this, this)
card = TangemCard(intent.getStringExtra(TangemCard.EXTRA_UID))
card!!.loadFromBundle(intent.extras!!.getBundle(TangemCard.EXTRA_CARD))
card = TangemCard(intent.getStringExtra(EXTRA_TANGEM_CARD_UID))
card!!.loadFromBundle(intent.extras!!.getBundle(EXTRA_TANGEM_CARD))
newPIN = intent.getStringExtra(Constant.EXTRA_NEW_PIN)
newPIN2 = intent.getStringExtra(Constant.EXTRA_NEW_PIN_2)
@ -81,7 +83,7 @@ class PinSwapActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProt
if (sUID == card!!.uid) {
isoDep.timeout = card!!.pauseBeforePIN2 + 65000
swapPinTask = SwapPINTask(this, card, nfcManager, newPIN, newPIN2, isoDep, this)
swapPinTask = SwapPINTask(card, NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, this, newPIN, newPIN2)
swapPinTask!!.start()
} else {
// Log.d(TAG, "Mismatch card UID (" + sUID + " instead of " + mCard!!.uid + ")")

View file

@ -10,10 +10,10 @@ import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.View
import com.tangem.data.network.CryptonitOtherApi
import com.tangem.tangemcard.reader.NfcManager
import com.tangem.tangemcard.data.Blockchain
import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemContext
import com.tangem.data.Blockchain
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_prepare_cryptonit_other_api_withdrawal.*
import java.io.IOException

View file

@ -13,8 +13,8 @@ import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import com.tangem.data.network.Cryptonit
import com.tangem.tangemcard.reader.NfcManager
import com.tangem.tangemcard.data.Blockchain
import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.data.Blockchain
import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemContext
import com.tangem.util.DecimalDigitsInputFilter
@ -145,7 +145,7 @@ class PrepareCryptonitWithdrawalActivity : AppCompatActivity(), NfcAdapter.Reade
rlProgressBar.visibility = View.VISIBLE
tvProgressDescription.text = getString(R.string.cryptonit_request_balance)
tvError.visibility = View.INVISIBLE
cryptonit!!.requestBalance(ctx.card!!.blockchain.currency)
cryptonit!!.requestBalance(ctx.blockchain.currency)
} else {
tvError.visibility = View.VISIBLE
tvError.text = getString(R.string.cryptonit_not_enough_account_data)

View file

@ -16,8 +16,8 @@ import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import com.tangem.data.network.Kraken
import com.tangem.tangemcard.reader.NfcManager
import com.tangem.tangemcard.data.Blockchain
import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.data.Blockchain
import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemContext
import com.tangem.wallet.R

View file

@ -12,8 +12,8 @@ import android.text.Html
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import com.tangem.tangemcard.reader.NfcManager
import com.tangem.tangemcard.data.Blockchain
import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.data.Blockchain
import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemContext
import com.tangem.wallet.R
@ -50,7 +50,7 @@ class PreparePaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
tvBalance.text = html
//TODO - to engine
if (ctx.card!!.blockchain == Blockchain.Token && engine.balance.currency!="ETH") {
if (ctx.blockchain == Blockchain.Token && engine.balance.currency!="ETH") {
rgIncFee!!.visibility = View.INVISIBLE
} else {
rgIncFee!!.visibility = View.VISIBLE
@ -152,7 +152,7 @@ class PreparePaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE_SCAN_QR && resultCode == Activity.RESULT_OK && data != null && data.extras!!.containsKey("QRCode")) {
var code = data.getStringExtra("QRCode")
when (ctx.card!!.blockchain) {
when (ctx.blockchain) {
Blockchain.Bitcoin -> {
if (code.contains("bitcoin:")) {
val tmp = code.split("bitcoin:".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()

View file

@ -12,12 +12,15 @@ import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.View
import android.widget.Toast
import com.tangem.App
import com.tangem.tangemcard.tasks.PurgeTask
import com.tangem.tangemcard.reader.CardProtocol
import com.tangem.tangemcard.reader.NfcManager
import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.domain.wallet.TangemContext
import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog
import com.tangem.presentation.dialog.WaitSecurityDelayDialog
import com.tangem.tangemcard.android.reader.NfcReader
import com.tangem.tangemcard.data.asBundle
import com.tangem.tangemcard.util.Util
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_purge.*
@ -30,7 +33,7 @@ class PurgeActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoc
}
private lateinit var ctx: TangemContext
private var nfcManager: NfcManager? = null
private lateinit var nfcManager: NfcManager
private var purgeTask: PurgeTask? = null
override fun onCreate(savedInstanceState: Bundle?) {
@ -79,7 +82,7 @@ class PurgeActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, CardProtoc
if (sUID == ctx.card!!.uid) {
isoDep.timeout = ctx.card!!.pauseBeforePIN2 + 65000
purgeTask = PurgeTask(this, ctx.card, nfcManager, isoDep, this)
purgeTask = PurgeTask(ctx.card, NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, this)
purgeTask!!.start()
} else {
// this Log.d(TAG, "Mismatch card UID (" + sUID + " instead of " + card.getUID() + ")");

View file

@ -11,11 +11,10 @@ import com.tangem.data.network.ElectrumRequest
import com.tangem.data.network.ServerApiElectrum
import com.tangem.data.network.ServerApiInfura
import com.tangem.data.network.model.InfuraResponse
import com.tangem.tangemcard.reader.NfcManager
import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.domain.wallet.*
import com.tangem.domain.wallet.eth.EthData
import com.tangem.tangemcard.data.Blockchain
import com.tangem.tangemcard.data.TangemCard
import com.tangem.data.Blockchain
import com.tangem.util.UtilHelper
import com.tangem.wallet.R
import java.io.IOException
@ -51,9 +50,9 @@ class SendTransactionActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
if (ctx.blockchain == Blockchain.Ethereum || ctx.blockchain == Blockchain.EthereumTestNet || ctx.blockchain == Blockchain.Token)
requestInfura(ServerApiInfura.INFURA_ETH_SEND_RAW_TRANSACTION, "")
else if (ctx.blockchain == Blockchain.Bitcoin || ctx.blockchain == Blockchain.BitcoinTestNet)
requestElectrum(ctx.card!!, ElectrumRequest.broadcast(ctx.coinData!!.wallet, tx))
requestElectrum(ctx, ElectrumRequest.broadcast(ctx.coinData!!.wallet, tx))
else if (ctx.blockchain == Blockchain.BitcoinCash)
requestElectrum(ctx.card!!, ElectrumRequest.broadcast(ctx.coinData!!.wallet, tx))
requestElectrum(ctx, ElectrumRequest.broadcast(ctx.coinData!!.wallet, tx))
// request electrum listener
val electrumBodyListener: ServerApiElectrum.ElectrumRequestDataListener = object : ServerApiElectrum.ElectrumRequestDataListener {
@ -151,9 +150,9 @@ class SendTransactionActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
finishWithError(getString(R.string.no_connection))
}
private fun requestElectrum(card: TangemCard, electrumRequest: ElectrumRequest) {
private fun requestElectrum(ctx: TangemContext, electrumRequest: ElectrumRequest) {
if (UtilHelper.isOnline(this)) {
serverApiElectrum.electrumRequestData(card, electrumRequest)
serverApiElectrum.electrumRequestData(ctx, electrumRequest)
} else
finishWithError(getString(R.string.no_connection))
}

View file

@ -13,15 +13,18 @@ import android.view.KeyEvent
import android.view.View
import android.widget.ProgressBar
import android.widget.Toast
import com.tangem.App
import com.tangem.domain.wallet.BTCUtils
import com.tangem.domain.wallet.CoinEngine
import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemContext
import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog
import com.tangem.presentation.dialog.WaitSecurityDelayDialog
import com.tangem.tangemcard.data.Blockchain
import com.tangem.data.Blockchain
import com.tangem.tangemcard.reader.CardProtocol
import com.tangem.tangemcard.reader.NfcManager
import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.tangemcard.android.reader.NfcReader
import com.tangem.tangemcard.data.asBundle
import com.tangem.tangemcard.tasks.SignTask
import com.tangem.tangemcard.util.Util
import com.tangem.wallet.R
@ -43,7 +46,7 @@ class SignPaymentActivity : AppCompatActivity(), NfcAdapter.ReaderCallback, Card
const val RESULT_INVALID_PIN = Activity.RESULT_FIRST_USER
}
private var nfcManager: NfcManager? = null
private lateinit var nfcManager: NfcManager
private lateinit var ctx: TangemContext
// private var signPaymentTask: SignPaymentTask? = null

View file

@ -7,9 +7,7 @@ import android.support.v7.app.AppCompatActivity
import com.tangem.App
import com.tangem.Constant
import com.tangem.di.Navigator
import com.tangem.domain.wallet.CoinData
import com.tangem.domain.wallet.TangemContext
import com.tangem.tangemcard.data.TangemCard
import com.tangem.presentation.fragment.VerifyCard
import com.tangem.wallet.R
import javax.inject.Inject

View file

@ -19,18 +19,17 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import com.tangem.App
import com.tangem.Constant
import com.tangem.tangemcard.data.local.LocalStorage
import com.tangem.tangemcard.data.local.PINStorage
import com.tangem.data.network.ElectrumRequest
import com.tangem.data.network.ServerApiCommon
import com.tangem.data.network.ServerApiElectrum
import com.tangem.data.network.ServerApiInfura
import com.tangem.tangemcard.data.network.model.CardVerifyAndGetInfo
import com.tangem.tangemserver.android.model.CardVerifyAndGetInfo
import com.tangem.data.network.model.InfuraResponse
import com.tangem.tangemcard.tasks.VerifyCardTask
import com.tangem.tangemcard.reader.CardProtocol
import com.tangem.tangemcard.reader.NfcManager
import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.domain.wallet.*
import com.tangem.domain.wallet.bch.BtcCashEngine
import com.tangem.domain.wallet.btc.BtcData
@ -42,11 +41,14 @@ import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog
import com.tangem.presentation.dialog.PINSwapWarningDialog
import com.tangem.presentation.dialog.ShowQRCodeDialog
import com.tangem.presentation.dialog.WaitSecurityDelayDialog
import com.tangem.tangemcard.data.Blockchain
import com.tangem.data.Blockchain
import com.tangem.tangemcard.android.reader.NfcReader
import com.tangem.tangemcard.data.EXTRA_TANGEM_CARD
import com.tangem.tangemcard.data.EXTRA_TANGEM_CARD_UID
import com.tangem.tangemcard.data.TangemCard
import com.tangem.tangemcard.data.network.Server
import com.tangem.tangemcard.data.network.ServerApiTangem
import com.tangem.tangemcard.data.loadFromBundle
import com.tangem.tangemcard.util.Util
import com.tangem.tangemserver.android.ServerApiTangem
import com.tangem.util.UtilHelper
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.fr_loaded_wallet.*
@ -60,7 +62,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
val TAG: String = LoadedWallet::class.java.simpleName
}
private var nfcManager: NfcManager? = null
private lateinit var nfcManager: NfcManager
private var serverApiCommon: ServerApiCommon = ServerApiCommon()
private var serverApiInfura: ServerApiInfura = ServerApiInfura()
@ -82,7 +84,6 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
private val activeColor: ColorStateList by lazy { resources.getColorStateList(R.color.colorAccent) }
private var requestCounter = 0
private var timerRepeatRefresh: Timer? = null
private lateinit var localStorage: LocalStorage
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -92,7 +93,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
lastTag = activity?.intent?.getParcelableExtra(Constant.EXTRA_LAST_DISCOVERED_TAG)
localStorage = activity?.let { LocalStorage(it) }!!
//localStorage = activity?.let { CardDataSubstitutionProvider(it) }!!
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@ -105,7 +106,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
if (ctx.blockchain == Blockchain.Token)
tvBalance.setSingleLine(false)
ivTangemCard.setImageBitmap(localStorage.getCardArtworkBitmap(ctx.card))
ivTangemCard.setImageBitmap(App.localStorage.getCardArtworkBitmap(ctx.card))
btnExtract.isEnabled = false
btnExtract.backgroundTintList = inactiveColor
@ -419,18 +420,20 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
if (!result.passed) return
if (localStorage.checkBatchInfoChanged(ctx.card!!, result)) {
if (App.localStorage.checkBatchInfoChanged(ctx.card!!, result)) {
Log.w(TAG, "Batch ${result.batch} info changed to '$result'")
ivTangemCard.setImageBitmap(localStorage.getCardArtworkBitmap(ctx.card!!))
localStorage.applySubstitution(ctx.card!!)
if (ctx.card!!.blockchain == Blockchain.Token || ctx.card!!.blockchain == Blockchain.Ethereum) {
ctx.card!!.setBlockchainIDFromCard(Blockchain.Ethereum.id)
ivTangemCard.setImageBitmap(App.localStorage.getCardArtworkBitmap(ctx.card!!))
App.localStorage.applySubstitution(ctx.card!!)
//todo - check this is not need after refactoring
// if (ctx.blockchain == Blockchain.Token || ctx.blockchain == Blockchain.Ethereum) {
// ctx.card!!.setBlockchainIDFromCard(Blockchain.Ethereum.id)
//ctx.blockchain=Blockchain.Ethereum
//engine=engine!!.swithToOtherEngine(Blockchain.Ethereum)
}
// }
refresh()
}
if (result.artwork != null && localStorage.checkNeedUpdateArtwork(result.artwork)) {
if (result.artwork != null && App.localStorage.checkNeedUpdateArtwork(result.artwork)) {
Log.w(TAG, "Artwork '${result.artwork!!.id}' updated, need download")
serverApiTangem.requestArtwork(result.artwork!!.id, result.artwork!!.getUpdateDate(), ctx.card!!)
updateViews()
@ -447,8 +450,8 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
// request artwork listener
val artworkListener: ServerApiTangem.ArtworkListener = object : ServerApiTangem.ArtworkListener {
override fun onSuccess(artworkId: String?, inputStream: InputStream?, updateDate: Date?) {
localStorage.updateArtwork(artworkId!!, inputStream!!, updateDate!!)
ivTangemCard.setImageBitmap(localStorage.getCardArtworkBitmap(ctx.card!!))
App.localStorage.updateArtwork(artworkId!!, inputStream!!, updateDate!!)
ivTangemCard.setImageBitmap(App.localStorage.getCardArtworkBitmap(ctx.card!!))
}
override fun onFail(message: String?) {
@ -538,12 +541,12 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
newPIN = ctx.card!!.pin
if (newPIN2 == "")
newPIN2 = PINStorage.getPIN2()
newPIN2 = App.pinStorage.piN2
val pinSwapWarningDialog = PINSwapWarningDialog()
pinSwapWarningDialog.setOnRefreshPage { (activity as LoadedWalletActivity).navigator.showPinSwap(context as Activity, newPIN, newPIN2) }
val bundle = Bundle()
if (!PINStorage.isDefaultPIN(newPIN) || !PINStorage.isDefaultPIN2(newPIN2))
if (!CardProtocol.isDefaultPIN(newPIN) || !CardProtocol.isDefaultPIN2(newPIN2))
bundle.putString(PINSwapWarningDialog.EXTRA_MESSAGE, getString(R.string.if_you_forget))
else
bundle.putString(PINSwapWarningDialog.EXTRA_MESSAGE, getString(R.string.if_you_use_default))
@ -563,9 +566,9 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
activity?.finish()
} else {
if (data != null && data.extras != null && data.extras!!.containsKey(TangemCard.EXTRA_UID) && data.extras!!.containsKey(TangemCard.EXTRA_CARD)) {
val updatedCard = TangemCard(data.getStringExtra(TangemCard.EXTRA_UID))
updatedCard.loadFromBundle(data.getBundleExtra(TangemCard.EXTRA_CARD))
if (data != null && data.extras != null && data.extras!!.containsKey(EXTRA_TANGEM_CARD_UID) && data.extras!!.containsKey(EXTRA_TANGEM_CARD)) {
val updatedCard = TangemCard(data.getStringExtra(EXTRA_TANGEM_CARD_UID))
updatedCard.loadFromBundle(data.getBundleExtra(EXTRA_TANGEM_CARD))
ctx.card = updatedCard
}
if (resultCode == CreateNewWalletActivity.RESULT_INVALID_PIN && requestPIN2Count < 2) {
@ -599,9 +602,9 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
activity?.finish()
} else {
if (data != null && data.extras != null && data.extras!!.containsKey(TangemCard.EXTRA_UID) && data.extras!!.containsKey(TangemCard.EXTRA_CARD)) {
val updatedCard = TangemCard(data.getStringExtra(TangemCard.EXTRA_UID))
updatedCard.loadFromBundle(data.getBundleExtra(TangemCard.EXTRA_CARD))
if (data != null && data.extras != null && data.extras!!.containsKey(EXTRA_TANGEM_CARD_UID) && data.extras!!.containsKey(EXTRA_TANGEM_CARD)) {
val updatedCard = TangemCard(data.getStringExtra(EXTRA_TANGEM_CARD_UID))
updatedCard.loadFromBundle(data.getBundleExtra(EXTRA_TANGEM_CARD))
ctx.card = updatedCard
}
if (resultCode == CreateNewWalletActivity.RESULT_INVALID_PIN && requestPIN2Count < 2) {
@ -627,9 +630,9 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
}
if (data != null && data.extras != null) {
if (data.extras!!.containsKey(TangemCard.EXTRA_UID) && data.extras!!.containsKey(TangemCard.EXTRA_CARD)) {
val updatedCard = TangemCard(data.getStringExtra(TangemCard.EXTRA_UID))
updatedCard.loadFromBundle(data.getBundleExtra(TangemCard.EXTRA_CARD))
if (data.extras!!.containsKey(EXTRA_TANGEM_CARD_UID) && data.extras!!.containsKey(EXTRA_TANGEM_CARD)) {
val updatedCard = TangemCard(data.getStringExtra(EXTRA_TANGEM_CARD_UID))
updatedCard.loadFromBundle(data.getBundleExtra(EXTRA_TANGEM_CARD))
ctx.card = updatedCard
}
if (data.extras!!.containsKey("message")) {
@ -773,10 +776,10 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
tvWallet.text = ctx.coinData!!.wallet
if (ctx.card!!.tokenSymbol.length > 1) {
val html = Html.fromHtml(ctx.card!!.blockchainName)
val html = Html.fromHtml(ctx.blockchainName)
tvBlockchain.text = html
} else
tvBlockchain.text = ctx.card!!.blockchainName
tvBlockchain.text = ctx.blockchainName
if (engine.hasBalanceInfo()) {
btnExtract.isEnabled = true
@ -842,7 +845,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
private fun requestElectrum(electrumRequest: ElectrumRequest) {
if (UtilHelper.isOnline(context as Activity)) {
requestCounter++
serverApiElectrum.electrumRequestData(ctx.card, electrumRequest)
serverApiElectrum.electrumRequestData(ctx, electrumRequest)
} else {
Toast.makeText(activity, getString(R.string.no_connection), Toast.LENGTH_SHORT).show()
srl?.isRefreshing = false
@ -898,7 +901,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
else
isoDep.timeout = 65000
verifyCardTask = VerifyCardTask(activity, ctx.card, nfcManager, isoDep, this)
verifyCardTask = VerifyCardTask(ctx.card, NfcReader(nfcManager, isoDep), App.localStorage, App.pinStorage, App.firmwaresStorage, this)
verifyCardTask?.start()
} catch (e: Exception) {

View file

@ -8,19 +8,23 @@ import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.content.ContextCompat
import android.text.Html
import android.text.format.DateUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.PopupMenu
import android.widget.Toast
import com.tangem.tangemcard.data.local.PINStorage
import com.tangem.tangemcard.reader.NfcManager
import com.tangem.App
import com.tangem.tangemcard.android.data.PINStorage
import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.Constant
import com.tangem.domain.wallet.*
import com.tangem.presentation.activity.*
import com.tangem.presentation.dialog.PINSwapWarningDialog
import com.tangem.tangemcard.data.Blockchain
import com.tangem.data.Blockchain
import com.tangem.tangemcard.data.TangemCard
import com.tangem.tangemcard.data.loadFromBundle
import com.tangem.tangemcard.reader.CardProtocol
import com.tangem.wallet.BuildConfig
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.fr_verify_card.*
@ -123,12 +127,12 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
Constant.REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN -> if (resultCode == Activity.RESULT_OK) {
if (newPIN == "") newPIN = ctx.card!!.pin
if (newPIN2 == "") newPIN2 = PINStorage.getPIN2()
if (newPIN2 == "") newPIN2 = App.pinStorage.getPIN2()
val pinSwapWarningDialog = PINSwapWarningDialog()
pinSwapWarningDialog.setOnRefreshPage { (activity as VerifyCardActivity).navigator.showPinSwap(context as Activity, newPIN, newPIN2) }
val bundle = Bundle()
if (!PINStorage.isDefaultPIN(newPIN) || !PINStorage.isDefaultPIN2(newPIN2))
if (!CardProtocol.isDefaultPIN(newPIN) || !CardProtocol.isDefaultPIN2(newPIN2))
bundle.putString(PINSwapWarningDialog.EXTRA_MESSAGE, getString(R.string.if_you_forget))
else
bundle.putString(PINSwapWarningDialog.EXTRA_MESSAGE, getString(R.string.if_you_use_default))
@ -203,7 +207,7 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
if (resultCode == Activity.RESULT_OK) {
srlVerifyCard.isRefreshing = true
ctx.coinData!!.clearInfo()
ctx.card!!.switchToInitialBlockchain()
//ctx.card!!.switchToInitialBlockchain()
updateViews()
}
@ -269,8 +273,9 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
}
tvIssuer.text = ctx.card!!.issuerDescription
tvCardRegistredDate.text = ctx.card!!.personalizationDateTimeDescription
val html = Html.fromHtml(ctx.card!!.blockchainName)
tvCardRegistredDate.text = DateUtils.formatDateTime(null, ctx.card!!.personalizationDateTime.time, DateUtils.FORMAT_SHOW_DATE or DateUtils.FORMAT_NUMERIC_DATE or DateUtils.FORMAT_SHOW_YEAR)
val html = Html.fromHtml(ctx.blockchainName)
tvBlockchain.text = html
tvValidationNode.text = ctx.coinData!!.validationNodeDescription
@ -350,7 +355,7 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
tvFeatures.text = features
if (ctx.card!!.useDefaultPIN1()!!) {
if (ctx.card!!.useDefaultPIN1()) {
imgPIN.setImageResource(R.drawable.unlock_pin1)
imgPIN.setOnClickListener { Toast.makeText(context, R.string.this_banknote_protected_default_PIN1_code, Toast.LENGTH_LONG).show() }
} else {

View file

@ -1 +1 @@
include ':app', ':tangemcard'
include ':app', ':tangemcard-android', ':tangemserver-android', ':tangemcard-common'

View file

@ -23,25 +23,25 @@ android {
}
dependencies {
implementation project(':tangemcard-common')
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
// implementation 'com.android.support:design:28.0.0'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.madgag.spongycastle:core:1.56.0.0'
implementation 'com.madgag.spongycastle:prov:1.56.0.0'
implementation 'com.scottyab:rootbeer-lib:0.0.7'
// implementation 'com.android.support:support-compat:28.0.0'
// implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'
// implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
// implementation 'com.squareup.retrofit2:retrofit:2.5.0'
// implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'
// implementation 'com.skyfishjy.ripplebackground:library:1.0.1'
// implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
implementation 'com.google.dagger:dagger:2.16'
implementation 'org.bitcoinj:bitcoinj-parent:0.14.7'
implementation 'org.bitcoinj:bitcoinj-core:0.14.7'
annotationProcessor 'com.google.dagger:dagger-compiler:2.16'
// implementation 'com.google.dagger:dagger:2.16'
// implementation 'org.bitcoinj:bitcoinj-parent:0.14.7'
// implementation 'org.bitcoinj:bitcoinj-core:0.14.7'
// annotationProcessor 'com.google.dagger:dagger-compiler:2.16'
// implementation 'info.hoang8f:android-segmented:1.0.6'
// implementation 'io.reactivex.rxjava2:rxjava:2.2.0'
// implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'

View file

@ -1,4 +1,4 @@
package com.tangem.tangemcard;
package com.tangem.tangemcard.android;
import android.content.Context;
import android.support.test.InstrumentationRegistry;

View file

@ -0,0 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tangem.tangemcard" >
<uses-feature
android:name="android.hardware.nfc"
android:required="true" />
<uses-permission android:name="android.permission.NFC" />
</manifest>

View file

@ -1,10 +1,11 @@
package com.tangem.tangemcard.data.local;
package com.tangem.tangemcard.android.data;
import android.content.Context;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.tangem.tangemcard.data.external.FirmwaresDigestsProvider;
import com.tangem.tangemcard.util.Util;
import java.io.IOException;
@ -12,14 +13,10 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
public class Firmwares {
public class Firmwares implements FirmwaresDigestsProvider {
private static JsonArray jaFirmwares = null;
public static boolean needInit() {
return jaFirmwares == null;
}
public static void init(Context context) {
public Firmwares(Context context) {
try (InputStream is = context.getAssets().open("fw_hashes.json")) {
try (InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
JsonParser parser = new JsonParser();
@ -30,21 +27,14 @@ public class Firmwares {
}
}
public static class VerifyCodeRecord {
public String hashAlg;
public int blockIndex;
public int blockCount;
public byte[] challenge;
public byte[] digest;
}
public static VerifyCodeRecord selectRandomVerifyCodeBlock(String firmwareVersion) throws IOException {
@Override
public FirmwaresDigestsProvider.VerifyCodeRecord selectRandomVerifyCodeBlock(String firmwareVersion) {
try {
for (int i = 0; i < jaFirmwares.size(); i++) {
JsonObject jsVersion = jaFirmwares.get(i).getAsJsonObject();
if (jsVersion.get("fw").getAsString().equals(firmwareVersion)) {
VerifyCodeRecord result = new VerifyCodeRecord();
FirmwaresDigestsProvider.VerifyCodeRecord result = new FirmwaresDigestsProvider.VerifyCodeRecord();
result.hashAlg = "sha-256";
JsonArray jsHashes = jsVersion.get(result.hashAlg).getAsJsonArray();
result.challenge = Util.hexToBytes(jsVersion.get("challenge").getAsString());

View file

@ -1,10 +1,11 @@
package com.tangem.tangemcard.data.local;
package com.tangem.tangemcard.android.data;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Base64;
import com.tangem.tangemcard.data.external.PINsProvider;
import com.tangem.tangemcard.reader.CardProtocol;
import java.util.ArrayList;
@ -17,7 +18,7 @@ import javax.crypto.Cipher;
* Global PIN Storage
*/
public class PINStorage {
public class PINStorage implements PINsProvider {
private static String mSavedPIN, mUserPIN, mLastUsedPIN, mEncryptedPIN, mPIN2;
private static SharedPreferences sharedPreferences = null;
@ -30,8 +31,8 @@ public class PINStorage {
mPIN2 = null;
}
public static List<String> getPINs() {
@Override
public List<String> getPINs() {
ArrayList<String> result = new ArrayList<>();
if (mLastUsedPIN != null) result.add(mLastUsedPIN);
if (mEncryptedPIN != null && !result.contains(mEncryptedPIN)) result.add(mEncryptedPIN);
@ -41,7 +42,7 @@ public class PINStorage {
return result;
}
public static void setLastUsedPIN(String PIN) {
public void setLastUsedPIN(String PIN) {
mLastUsedPIN = PIN;
}
@ -177,18 +178,10 @@ public class PINStorage {
editor.apply();
}
public static String getPIN2() {
public String getPIN2() {
return mPIN2;
}
public static boolean isDefaultPIN(String pin) {
return (CardProtocol.DefaultPIN.equals(pin));
}
public static boolean isDefaultPIN2(String pin2) {
return (CardProtocol.DefaultPIN2.equals(pin2));
}
public static String getDefaultPIN() {
return CardProtocol.DefaultPIN;
}

View file

@ -1,4 +1,4 @@
package com.tangem.tangemcard.data.nfc
package com.tangem.tangemcard.android.nfc
import android.os.Build

View file

@ -1,4 +1,4 @@
package com.tangem.tangemcard.data.nfc
package com.tangem.tangemcard.android.nfc
enum class NFCLocation(val codename: String, val fullName: String, val orientation: Int, val x: Int, val y: Int, val z: Int) {
model1("sailfish", "Google Pixel", 0, 65, 25, 0),

View file

@ -1,4 +1,4 @@
package com.tangem.tangemcard.presentation.dialog
package com.tangem.tangemcard.android.presentation.dialog
import android.app.Dialog
import android.content.Intent

View file

@ -1,4 +1,4 @@
package com.tangem.tangemcard.reader;
package com.tangem.tangemcard.android.reader;
import android.Manifest;
import android.annotation.TargetApi;
@ -16,7 +16,7 @@ import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
import com.tangem.tangemcard.presentation.dialog.NfcEnableDialog;
import com.tangem.tangemcard.android.presentation.dialog.NfcEnableDialog;
import java.io.IOException;

View file

@ -0,0 +1,41 @@
package com.tangem.tangemcard.android.reader
import android.nfc.tech.IsoDep
data class NfcReader(
val nfcManager: NfcManager,
val isoDep: IsoDep
) : com.tangem.tangemcard.reader.NfcReader {
override fun getId(): ByteArray {
return isoDep.tag.id
}
override fun setTimeout(timeout: Int) {
isoDep.timeout = timeout
}
override fun getTimeout(): Int {
return isoDep.timeout
}
override fun transceive(data: ByteArray?): ByteArray {
return isoDep.transceive(data)
}
override fun ignoreTag() {
nfcManager.ignoreTag(isoDep.tag)
}
override fun notifyReadResult(success: Boolean) {
nfcManager.notifyReadResult(success)
}
override fun connect() {
val timeout = isoDep.timeout
isoDep.connect()
isoDep.close()
isoDep.connect()
isoDep.timeout = timeout
}
}

View file

@ -0,0 +1,150 @@
package com.tangem.tangemcard.data
import android.os.Bundle
import com.tangem.tangemcard.util.Log
import java.util.*
const val EXTRA_TANGEM_CARD = "Card"
const val EXTRA_TANGEM_CARD_UID = "UID"
fun TangemCard.loadFromBundle(B: Bundle) {
uid = B.getString("UID")
cid = B.getByteArray("CID")
pin = B.getString("PIN")
PIN2 = TangemCard.PIN2_Mode.valueOf(B.getString("PIN2")!!)
status = TangemCard.Status.valueOf(B.getString("Status")!!)
blockchainID = B.getString("Blockchain")
tokensDecimal = B.getInt("TokensDecimal", 18)
tokenSymbol = B.getString("TokenSymbol", "")
contractAddress = B.getString("ContractAddress", "")
// if (B.containsKey("BlockchainName"))
// blockchainName = B.getString("BlockchainName", "");
if (B.containsKey("dtPersonalization")) {
personalizationDateTime = Date(B.getLong("dtPersonalization"))
}
remainingSignatures = B.getInt("RemainingSignatures")
maxSignatures = B.getInt("MaxSignatures")
health = B.getInt("health")
if (B.containsKey("settingsMask")) settingsMask = B.getInt("settingsMask")
pauseBeforePIN2 = B.getInt("pauseBeforePIN2")
if (B.containsKey("signingMethod"))
setSigningMethod(TangemCard.SigningMethod.valueOf(B.getString("signingMethod")!!).ID)
if (B.containsKey("Manufacturer"))
setManufacturer(Manufacturer.valueOf(B.getString("Manufacturer")!!), B.getBoolean("ManufacturerConfirmed", false))
if (B.containsKey("EncryptionMode"))
encryptionMode = TangemCard.EncryptionMode.valueOf(B.getString("EncryptionMode")!!)
else
encryptionMode = null
if (B.containsKey("SignedHashes")) signedHashes = B.getInt("SignedHashes")
if (B.containsKey("Issuer")) setIssuer(B.getString("Issuer"), B.getByteArray("IssuerPublicDataKey"))
if (B.containsKey("FirmwareVersion")) firmwareVersion = B.getString("FirmwareVersion")
if (B.containsKey("Batch")) batch = B.getString("Batch")
isCardPublicKeyValid = B.getBoolean("CardPublicKeyValid")
if (B.containsKey("CardPublicKey")) cardPublicKey = B.getByteArray("CardPublicKey")
if (B.containsKey("OfflineBalance")) offlineBalance = B.getByteArray("OfflineBalance")
else clearOfflineBalance()
if (B.containsKey("Denomination") && B.containsKey("DenominationText")) {
setDenomination(B.getByteArray("Denomination"), B.getString("DenominationText"))
} else if (B.containsKey("Denomination")) {
setDenomination(B.getByteArray("Denomination"), "N/A")
} else clearDenomination()
if (B.containsKey("IssuerData") && B.containsKey("IssuerDataSignature"))
setIssuerData(B.getByteArray("IssuerData"), B.getByteArray("IssuerDataSignature"))
else setIssuerData(null, null)
if (B.containsKey("NeedWriteIssuerData"))
needWriteIssuerData = B.getBoolean("NeedWriteIssuerData")
isWalletPublicKeyValid = B.getBoolean("WalletPublicKeyValid")
if (B.containsKey("PublicKey")) {
walletPublicKey = B.getByteArray("PublicKey")
}
if (B.containsKey("PublicKeyRar")) {
walletPublicKeyRar = B.getByteArray("PublicKeyRar")
}
if (B.containsKey("codeConfirmed"))
isCodeConfirmed = B.getBoolean("codeConfirmed")
if (B.containsKey("onlineVerified"))
isOnlineVerified = B.getBoolean("onlineVerified")
if (B.containsKey("onlineValidated"))
isOnlineValidated = B.getBoolean("onlineValidated")
}
val TangemCard.asBundle: Bundle
get() {
val bundle = Bundle()
saveToBundle(bundle)
return bundle
}
fun TangemCard.saveToBundle(B: Bundle) {
try {
B.putString("UID", uid)
B.putByteArray("CID", cid)
B.putString("PIN", pin)
B.putString("PIN2", PIN2.name)
B.putString("Status", status.name)
B.putString("Blockchain", blockchainID)
B.putInt("TokensDecimal", tokensDecimal)
B.putString("TokenSymbol", tokenSymbol)
B.putString("ContractAddress", contractAddress)
if (personalizationDateTime != null) B.putLong("dtPersonalization", personalizationDateTime.time)
B.putInt("RemainingSignatures", remainingSignatures)
B.putInt("MaxSignatures", maxSignatures)
B.putInt("Health", health)
if (settingsMask != null) B.putInt("settingsMask", settingsMask)
B.putInt("pauseBeforePIN2", pauseBeforePIN2)
if (signingMethod != null) B.putString("signingMethod", signingMethod.name)
if (manufacturer != null) B.putString("Manufacturer", manufacturer.name)
if (encryptionMode != null) B.putString("EncryptionMode", encryptionMode.name)
if (issuer != null) B.putString("Issuer", issuer.getID())
if (issuerPublicDataKey != null) B.putByteArray("IssuerPublicDataKey", issuerPublicDataKey)
if (firmwareVersion != null) B.putString("FirmwareVersion", firmwareVersion)
if (batch != null) B.putString("Batch", batch)
B.putBoolean("ManufacturerConfirmed", isManufacturerConfirmed)
B.putBoolean("CardPublicKeyValid", isCardPublicKeyValid)
B.putByteArray("CardPublicKey", cardPublicKey)
B.putInt("SignedHashes", signedHashes)
B.putBoolean("WalletPublicKeyValid", isWalletPublicKeyValid)
if (walletPublicKey != null)
B.putByteArray("PublicKey", walletPublicKey)
if (walletPublicKeyRar != null)
B.putByteArray("PublicKeyRar", walletPublicKeyRar)
if (offlineBalance != null) B.putByteArray("OfflineBalance", offlineBalance)
if (denomination != null) B.putByteArray("Denomination", denomination)
if (denominationText != null) B.putString("DenominationText", denominationText)
if (issuerData != null && issuerDataSignature != null) {
B.putByteArray("IssuerData", issuerData)
B.putByteArray("IssuerDataSignature", issuerDataSignature)
B.putBoolean("NeedWriteIssuerData", needWriteIssuerData)
}
if (isCodeConfirmed != null)
B.putBoolean("codeConfirmed", isCodeConfirmed)
if (isOnlineVerified != null)
B.putBoolean("onlineVerified", isOnlineVerified)
if (isOnlineValidated != null)
B.putBoolean("onlineValidated", isOnlineValidated)
} catch (e: Exception) {
Log.e("Can't save to bundle ", e.message)
}
}

View file

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 115 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 135 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 536 B

After

Width:  |  Height:  |  Size: 536 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Before After
Before After

View file

@ -0,0 +1,17 @@
package com.tangem.tangemcard.android;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

1
tangemcard-common/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/build

View file

@ -0,0 +1,12 @@
apply plugin: 'java-library'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.madgag.spongycastle:core:1.56.0.0'
implementation 'com.madgag.spongycastle:prov:1.56.0.0'
}
sourceCompatibility = "7"
targetCompatibility = "7"

View file

@ -1,16 +1,8 @@
package com.tangem.tangemcard.data;
import android.content.Context;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.tangem.tangemcard.reader.CardCrypto;
import com.tangem.tangemcard.util.Util;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -27,7 +19,7 @@ public class Issuer {
byte[] getPrivateKey() throws Exception {
if (privateKey != null) {
return CardCrypto.GeneratePublicKey(Util.hexToBytes(privateKey));
return Util.hexToBytes(privateKey);
} else {
throw new Exception("No private key!");
}
@ -47,8 +39,8 @@ public class Issuer {
}
private String id;
private String officialName;
public String id;
public String officialName;
private KeyPair dataKey;
private KeyPair transactionKey;
@ -58,27 +50,16 @@ public class Issuer {
private static List<Issuer> instances = new ArrayList<>();
public static boolean needInit() {
return instances.size() == 0;
static {
Issuer unknown = new Issuer();
unknown.id = "UNKNOWN";
unknown.officialName = "UNKNOWN";
instances.add(unknown);
}
public static void init(Context context) {
try {
Issuer unknown = new Issuer();
unknown.id = "UNKNOWN";
unknown.officialName = "UNKNOWN";
try (InputStream is = context.getAssets().open("issuers.json")) {
try (InputStreamReader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
Type listType = new TypeToken<List<Issuer>>() {
}.getType();
instances = new Gson().fromJson(reader, listType);
}
}
instances.add(0, unknown);
} catch (Exception e) {
e.printStackTrace();
}
public static void fillIssuers(List<Issuer> issuers)
{
instances.addAll(issuers);
}
public byte[] getPublicDataKey() throws Exception {

View file

@ -1,10 +1,6 @@
package com.tangem.tangemcard.data;
import android.os.Bundle;
import android.util.Log;
import com.google.common.base.Strings;
import com.tangem.tangemcard.data.local.PINStorage;
import com.tangem.tangemcard.reader.CardProtocol;
import com.tangem.tangemcard.reader.SettingsMask;
import com.tangem.tangemcard.util.Util;
@ -16,9 +12,6 @@ import java.util.Date;
public class TangemCard {
public static final String EXTRA_CARD = "Card";
public static final String EXTRA_UID = "UID";
private byte[] CID;
private Status status;
private String UID;
@ -37,50 +30,10 @@ public class TangemCard {
return blockchainID;
}
public Blockchain getBlockchain() {
return Blockchain.fromId(blockchainID);
}
public void setBlockchain(Blockchain blockchain) {
blockchainID = blockchain.getID();
}
public void setBlockchainID(String blockchainID) {
this.blockchainID = blockchainID;
}
public void addTokenToBlockchainName() {
String token = getTokenSymbol();
if (Strings.isNullOrEmpty(token))
return;
String oldName = getBlockchain().getOfficialName();
//String newName = String.format("%s - %s ERC20 token", token, oldName);
String newName = token + " <br><small><small> " + oldName + " ERC20 token</small></small>";
blockchainName = newName;
}
private String blockchainName = "";
public String getBlockchainName() {
if (Strings.isNullOrEmpty(blockchainName))
return getBlockchain().getOfficialName();
return blockchainName;
}
public void setBlockchainIDFromCard(String blockchainID) {
if (Blockchain.fromId(blockchainID) != Blockchain.Ethereum && Blockchain.fromId(blockchainID) != Blockchain.EthereumTestNet)
this.blockchainID = blockchainID;
if (isToken()) {
this.blockchainID = Blockchain.Token.getID();
addTokenToBlockchainName();
} else {
this.blockchainID = blockchainID;
}
}
public void setWalletPublicKey(byte[] publicKey) {
pbWalletKey = publicKey;
}
@ -189,10 +142,10 @@ public class TangemCard {
this.PIN = PIN;
}
public void switchToInitialBlockchain() {
if (tokenSymbol.length() > 1)
blockchainID = Blockchain.Token.getID(); // Reset blockchain to Token from ETH for token cards with zero token balance on it
}
// public void switchToInitialBlockchain() {
// if (tokenSymbol.length() > 1)
// blockchainID = Blockchain.Token.getID(); // Reset blockchain to Token from ETH for token cards with zero token balance on it
// }
public Date getPersonalizationDateTime() {
return dtPersonalization;
@ -202,12 +155,12 @@ public class TangemCard {
this.dtPersonalization = dtPersonalization;
}
public String getPersonalizationDateTimeDescription() {
return Util.formatDate(dtPersonalization);
}
private int health = 0;
public int getHealth() {
return health;
}
public void setHealth(int health) {
if (health > this.health) this.health = health;
}
@ -216,15 +169,19 @@ public class TangemCard {
return health == 0;
}
private Issuer issuer = Issuer.Unknown();
private byte[] issuerPublicDataKey = null;
private String issuerID = null;
// public void setIssuer(Issuer issuer) {
// this.issuer = issuer;
// }
public byte[] getIssuerPublicDataKey() {
return issuerPublicDataKey;
}
private Issuer issuer = Issuer.Unknown();
public void setIssuer(String issuerID, byte[] issuerPublicDataKey) {
this.issuerPublicDataKey = issuerPublicDataKey;
this.issuerID = issuerID;
this.issuer = Issuer.FindIssuer(issuerID, issuerPublicDataKey);
}
@ -232,14 +189,11 @@ public class TangemCard {
return issuer;
}
public byte[] getIssuerPublicDataKey() {
return issuerPublicDataKey;
}
public String getIssuerDescription() {
return issuer.getOfficialName();
}
String contractAddress = "";
public void setContractAddress(String address) {
@ -261,7 +215,7 @@ public class TangemCard {
}
public boolean isToken() {
return !Strings.isNullOrEmpty(tokenSymbol);
return !(tokenSymbol == null || tokenSymbol.isEmpty());
}
int tokensDecimal = 18;
@ -317,6 +271,10 @@ public class TangemCard {
private Integer settingsMask = null;
public Integer getSettingsMask() {
return settingsMask;
}
public void setSettingsMask(int settingsMask) {
this.settingsMask = settingsMask;
}
@ -341,15 +299,15 @@ public class TangemCard {
return (settingsMask & SettingsMask.UseCVC) != 0;
}
public Boolean useDefaultPIN1() {
return PINStorage.isDefaultPIN(getPIN());
}
public Boolean useSmartSecurityDelay() {
if (settingsMask == null) return null;
return (settingsMask & SettingsMask.SmartSecurityDelay) != 0;
}
public Boolean useDefaultPIN1() {
return CardProtocol.isDefaultPIN(getPIN());
}
public enum PIN2_Mode {Unchecked, DefaultPIN2, CustomPIN2}
public PIN2_Mode PIN2 = PIN2_Mode.Unchecked;
@ -609,163 +567,163 @@ public class TangemCard {
DenominationText = null;
}
public Bundle getAsBundle() {
Bundle B = new Bundle();
saveToBundle(B);
return B;
}
public void saveToBundle(Bundle B) {
try {
B.putString("UID", UID);
B.putByteArray("CID", CID);
B.putString("PIN", PIN);
B.putString("PIN2", PIN2.name());
B.putString("Status", status.name());
B.putString("Blockchain", blockchainID);
B.putString("BlockchainName", blockchainName);
B.putInt("TokensDecimal", tokensDecimal);
B.putString("TokenSymbol", tokenSymbol);
B.putString("ContractAddress", contractAddress);
if (dtPersonalization != null) B.putLong("dtPersonalization", dtPersonalization.getTime());
B.putInt("RemainingSignatures", remainingSignatures);
B.putInt("MaxSignatures", maxSignatures);
B.putInt("Health", health);
if (settingsMask != null) B.putInt("settingsMask", settingsMask);
B.putInt("pauseBeforePIN2", pauseBeforePIN2);
if (signingMethod != null) B.putString("signingMethod", signingMethod.name());
if (manufacturer != null) B.putString("Manufacturer", manufacturer.name());
if (encryptionMode != null) B.putString("EncryptionMode", encryptionMode.name());
if (issuer != null) B.putString("Issuer", issuer.getID());
if (issuerPublicDataKey != null) B.putByteArray("IssuerPublicDataKey", issuerPublicDataKey);
if (firmwareVersion != null) B.putString("FirmwareVersion", firmwareVersion);
if (batch != null) B.putString("Batch", batch);
B.putBoolean("ManufacturerConfirmed", manufacturerConfirmed);
B.putBoolean("CardPublicKeyValid", isCardPublicKeyValid());
B.putByteArray("CardPublicKey", getCardPublicKey());
B.putInt("SignedHashes", getSignedHashes());
B.putBoolean("WalletPublicKeyValid", isWalletPublicKeyValid());
if (pbWalletKey != null)
B.putByteArray("PublicKey", pbWalletKey);
if (pbWalletKeyRar != null)
B.putByteArray("PublicKeyRar", pbWalletKeyRar);
if (getOfflineBalance() != null) B.putByteArray("OfflineBalance", getOfflineBalance());
if (getDenomination() != null) B.putByteArray("Denomination", getDenomination());
if (getDenominationText() != null) B.putString("DenominationText", getDenominationText());
if (getIssuerData() != null && getIssuerDataSignature() != null) {
B.putByteArray("IssuerData", getIssuerData());
B.putByteArray("IssuerDataSignature", getIssuerDataSignature());
B.putBoolean("NeedWriteIssuerData", getNeedWriteIssuerData());
}
if (codeConfirmed != null)
B.putBoolean("codeConfirmed", codeConfirmed);
if (codeConfirmed != null)
B.putBoolean("codeConfirmed", codeConfirmed);
if (onlineVerified != null)
B.putBoolean("onlineVerified", onlineVerified);
if (onlineValidated != null)
B.putBoolean("onlineValidated", onlineValidated);
if (codeConfirmed != null)
B.putBoolean("codeConfirmed", codeConfirmed);
if (codeConfirmed != null)
B.putBoolean("codeConfirmed", codeConfirmed);
if (onlineVerified != null)
B.putBoolean("onlineVerified", onlineVerified);
if (onlineValidated != null)
B.putBoolean("onlineValidated", onlineValidated);
} catch (Exception e) {
Log.e("Can't save to bundle ", e.getMessage());
}
}
public void loadFromBundle(Bundle B) {
UID = B.getString("UID");
CID = B.getByteArray("CID");
PIN = B.getString("PIN");
PIN2 = PIN2_Mode.valueOf(B.getString("PIN2"));
status = Status.valueOf(B.getString("Status"));
blockchainID = B.getString("Blockchain");
tokensDecimal = B.getInt("TokensDecimal", 18);
tokenSymbol = B.getString("TokenSymbol", "");
contractAddress = B.getString("ContractAddress", "");
if (B.containsKey("BlockchainName"))
blockchainName = B.getString("BlockchainName", "");
if (B.containsKey("dtPersonalization")) {
dtPersonalization = new Date(B.getLong("dtPersonalization"));
}
remainingSignatures = B.getInt("RemainingSignatures");
maxSignatures = B.getInt("MaxSignatures");
health = B.getInt("health");
if (B.containsKey("settingsMask")) settingsMask = B.getInt("settingsMask");
pauseBeforePIN2 = B.getInt("pauseBeforePIN2");
if (B.containsKey("signingMethod"))
signingMethod = SigningMethod.valueOf(B.getString("signingMethod"));
if (B.containsKey("Manufacturer"))
manufacturer = Manufacturer.valueOf(B.getString("Manufacturer"));
manufacturerConfirmed = B.getBoolean("ManufacturerConfirmed");
if (B.containsKey("EncryptionMode"))
encryptionMode = EncryptionMode.valueOf(B.getString("EncryptionMode"));
else
encryptionMode = null;
if (B.containsKey("SignedHashes")) setSignedHashes(B.getInt("SignedHashes"));
if (B.containsKey("Issuer")) issuer = Issuer.FindIssuer(B.getString("Issuer"));
if (B.containsKey("IssuerPublicDataKey"))
issuerPublicDataKey = B.getByteArray("IssuerPublicDataKey");
if (B.containsKey("FirmwareVersion")) firmwareVersion = B.getString("FirmwareVersion");
if (B.containsKey("Batch")) batch = B.getString("Batch");
cardPublicKeyValid = B.getBoolean("CardPublicKeyValid");
if (B.containsKey("CardPublicKey")) setCardPublicKey(B.getByteArray("CardPublicKey"));
if (B.containsKey("OfflineBalance")) setOfflineBalance(B.getByteArray("OfflineBalance"));
else clearOfflineBalance();
if (B.containsKey("Denomination") && B.containsKey("DenominationText")) {
setDenomination(B.getByteArray("Denomination"), B.getString("DenominationText"));
} else if (B.containsKey("Denomination")) {
setDenomination(B.getByteArray("Denomination"), "N/A");
} else clearDenomination();
if (B.containsKey("IssuerData") && B.containsKey("IssuerDataSignature"))
setIssuerData(B.getByteArray("IssuerData"), B.getByteArray("IssuerDataSignature"));
else setIssuerData(null, null);
if (B.containsKey("NeedWriteIssuerData"))
setNeedWriteIssuerData(B.getBoolean("NeedWriteIssuerData"));
walletPublicKeyValid = B.getBoolean("WalletPublicKeyValid");
if (B.containsKey("PublicKey")) {
pbWalletKey = B.getByteArray("PublicKey");
}
if (B.containsKey("PublicKeyRar")) {
pbWalletKeyRar = B.getByteArray("PublicKeyRar");
}
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 Bundle getAsBundle() {
// Bundle B = new Bundle();
// saveToBundle(B);
// return B;
// }
//
// public void saveToBundle(Bundle B) {
// try {
// B.putString("UID", UID);
// B.putByteArray("CID", CID);
// B.putString("PIN", PIN);
// B.putString("PIN2", PIN2.name());
// B.putString("Status", status.name());
// B.putString("Blockchain", blockchainID);
// B.putString("BlockchainName", blockchainName);
// B.putInt("TokensDecimal", tokensDecimal);
// B.putString("TokenSymbol", tokenSymbol);
// B.putString("ContractAddress", contractAddress);
// if (dtPersonalization != null) B.putLong("dtPersonalization", dtPersonalization.getTime());
// B.putInt("RemainingSignatures", remainingSignatures);
// B.putInt("MaxSignatures", maxSignatures);
// B.putInt("Health", health);
// if (settingsMask != null) B.putInt("settingsMask", settingsMask);
// B.putInt("pauseBeforePIN2", pauseBeforePIN2);
// if (signingMethod != null) B.putString("signingMethod", signingMethod.name());
// if (manufacturer != null) B.putString("Manufacturer", manufacturer.name());
// if (encryptionMode != null) B.putString("EncryptionMode", encryptionMode.name());
// if (issuer != null) B.putString("Issuer", issuer.getID());
// if (issuerPublicDataKey != null) B.putByteArray("IssuerPublicDataKey", issuerPublicDataKey);
// if (firmwareVersion != null) B.putString("FirmwareVersion", firmwareVersion);
// if (batch != null) B.putString("Batch", batch);
// B.putBoolean("ManufacturerConfirmed", manufacturerConfirmed);
// B.putBoolean("CardPublicKeyValid", isCardPublicKeyValid());
// B.putByteArray("CardPublicKey", getCardPublicKey());
//
// B.putInt("SignedHashes", getSignedHashes());
// B.putBoolean("WalletPublicKeyValid", isWalletPublicKeyValid());
// if (pbWalletKey != null)
// B.putByteArray("PublicKey", pbWalletKey);
// if (pbWalletKeyRar != null)
// B.putByteArray("PublicKeyRar", pbWalletKeyRar);
//
// if (getOfflineBalance() != null) B.putByteArray("OfflineBalance", getOfflineBalance());
//
// if (getDenomination() != null) B.putByteArray("Denomination", getDenomination());
// if (getDenominationText() != null) B.putString("DenominationText", getDenominationText());
//
// if (getIssuerData() != null && getIssuerDataSignature() != null) {
// B.putByteArray("IssuerData", getIssuerData());
// B.putByteArray("IssuerDataSignature", getIssuerDataSignature());
// B.putBoolean("NeedWriteIssuerData", getNeedWriteIssuerData());
// }
//
// if (codeConfirmed != null)
// B.putBoolean("codeConfirmed", codeConfirmed);
//
// if (codeConfirmed != null)
// B.putBoolean("codeConfirmed", codeConfirmed);
//
// if (onlineVerified != null)
// B.putBoolean("onlineVerified", onlineVerified);
//
// if (onlineValidated != null)
// B.putBoolean("onlineValidated", onlineValidated);
//
// if (codeConfirmed != null)
// B.putBoolean("codeConfirmed", codeConfirmed);
//
// if (codeConfirmed != null)
// B.putBoolean("codeConfirmed", codeConfirmed);
//
// if (onlineVerified != null)
// B.putBoolean("onlineVerified", onlineVerified);
//
// if (onlineValidated != null)
// B.putBoolean("onlineValidated", onlineValidated);
// } catch (Exception e) {
// Log.e("Can't save to bundle ", e.getMessage());
// }
//
// }
//
// public void loadFromBundle(Bundle B) {
// UID = B.getString("UID");
// CID = B.getByteArray("CID");
// PIN = B.getString("PIN");
// PIN2 = PIN2_Mode.valueOf(B.getString("PIN2"));
// status = Status.valueOf(B.getString("Status"));
// blockchainID = B.getString("Blockchain");
// tokensDecimal = B.getInt("TokensDecimal", 18);
// tokenSymbol = B.getString("TokenSymbol", "");
// contractAddress = B.getString("ContractAddress", "");
// if (B.containsKey("BlockchainName"))
// blockchainName = B.getString("BlockchainName", "");
// if (B.containsKey("dtPersonalization")) {
// dtPersonalization = new Date(B.getLong("dtPersonalization"));
// }
// remainingSignatures = B.getInt("RemainingSignatures");
// maxSignatures = B.getInt("MaxSignatures");
// health = B.getInt("health");
// if (B.containsKey("settingsMask")) settingsMask = B.getInt("settingsMask");
// pauseBeforePIN2 = B.getInt("pauseBeforePIN2");
// if (B.containsKey("signingMethod"))
// signingMethod = SigningMethod.valueOf(B.getString("signingMethod"));
// if (B.containsKey("Manufacturer"))
// manufacturer = Manufacturer.valueOf(B.getString("Manufacturer"));
// manufacturerConfirmed = B.getBoolean("ManufacturerConfirmed");
// if (B.containsKey("EncryptionMode"))
// encryptionMode = EncryptionMode.valueOf(B.getString("EncryptionMode"));
// else
// encryptionMode = null;
//
// if (B.containsKey("SignedHashes")) setSignedHashes(B.getInt("SignedHashes"));
//
// if (B.containsKey("Issuer")) issuer = Issuer.FindIssuer(B.getString("Issuer"));
// if (B.containsKey("IssuerPublicDataKey"))
// issuerPublicDataKey = B.getByteArray("IssuerPublicDataKey");
//
// if (B.containsKey("FirmwareVersion")) firmwareVersion = B.getString("FirmwareVersion");
// if (B.containsKey("Batch")) batch = B.getString("Batch");
//
// cardPublicKeyValid = B.getBoolean("CardPublicKeyValid");
// if (B.containsKey("CardPublicKey")) setCardPublicKey(B.getByteArray("CardPublicKey"));
//
// if (B.containsKey("OfflineBalance")) setOfflineBalance(B.getByteArray("OfflineBalance"));
// else clearOfflineBalance();
//
// if (B.containsKey("Denomination") && B.containsKey("DenominationText")) {
// setDenomination(B.getByteArray("Denomination"), B.getString("DenominationText"));
// } else if (B.containsKey("Denomination")) {
// setDenomination(B.getByteArray("Denomination"), "N/A");
// } else clearDenomination();
//
// if (B.containsKey("IssuerData") && B.containsKey("IssuerDataSignature"))
// setIssuerData(B.getByteArray("IssuerData"), B.getByteArray("IssuerDataSignature"));
// else setIssuerData(null, null);
//
// if (B.containsKey("NeedWriteIssuerData"))
// setNeedWriteIssuerData(B.getBoolean("NeedWriteIssuerData"));
//
// walletPublicKeyValid = B.getBoolean("WalletPublicKeyValid");
// if (B.containsKey("PublicKey")) {
// pbWalletKey = B.getByteArray("PublicKey");
// }
// if (B.containsKey("PublicKeyRar")) {
// pbWalletKeyRar = B.getByteArray("PublicKeyRar");
// }
//
// 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 enum EncryptionMode {
None((byte) 0x0), Fast((byte) 0x1), Strong((byte) 0x2);

View file

@ -0,0 +1,7 @@
package com.tangem.tangemcard.data.external;
import com.tangem.tangemcard.data.TangemCard;
public interface CardDataSubstitutionProvider {
void applySubstitution(TangemCard card);
}

View file

@ -0,0 +1,14 @@
package com.tangem.tangemcard.data.external;
public interface FirmwaresDigestsProvider {
VerifyCodeRecord selectRandomVerifyCodeBlock(String firmwareVersion);
class VerifyCodeRecord {
public String hashAlg;
public int blockIndex;
public int blockCount;
public byte[] challenge;
public byte[] digest;
}
}

View file

@ -0,0 +1,11 @@
package com.tangem.tangemcard.data.external;
import java.util.List;
public interface PINsProvider {
String getPIN2();
void setLastUsedPIN(String pin);
List<String> getPINs();
}

View file

@ -1,7 +1,6 @@
package com.tangem.tangemcard.reader;
import android.util.Log;
import com.tangem.tangemcard.util.Log;
import com.tangem.tangemcard.util.PBKDF2;
import com.tangem.tangemcard.util.Util;

View file

@ -1,14 +1,8 @@
package com.tangem.tangemcard.reader;
import android.content.Context;
import android.nfc.Tag;
import android.nfc.TagLostException;
import android.nfc.tech.IsoDep;
import android.util.Log;
import com.tangem.tangemcard.data.TangemCard;
import com.tangem.tangemcard.data.local.Firmwares;
import com.tangem.tangemcard.data.Manufacturer;
import com.tangem.tangemcard.util.Log;
import com.tangem.tangemcard.util.Util;
import org.spongycastle.jce.ECNamedCurveTable;
@ -103,14 +97,8 @@ public class CardProtocol {
private static final int SW_PIN_ERROR = SW.INVALID_PARAMS;
private IsoDep mIsoDep;
private NfcReader mIsoDep;
/**
* @return Android NFC tag object
*/
public Tag getTag() {
return mIsoDep.getTag();
}
public static final String DefaultPIN = "000000";
public static final String DefaultPIN2 = "000";
@ -124,9 +112,17 @@ public class CardProtocol {
}
}
public static boolean isDefaultPIN(String pin) {
return (DefaultPIN.equals(pin));
}
public static boolean isDefaultPIN2(String pin2) {
return (DefaultPIN2.equals(pin2));
}
private TangemCard mCard;
private Exception mError;
private Context mContext;
/**
* Set occurred error
@ -148,15 +144,12 @@ public class CardProtocol {
/**
* Constructor
*
* @param context - Android context
* @param isoDep - Android NFC tag
* @param reader - NFC Reader interface
* @param card - TangemCard object, stored data from previous reading or null for reading a card for the first time
* @param notifications - UI notification callbacks
*/
public CardProtocol(Context context, IsoDep isoDep, TangemCard card, Notifications notifications) {
mContext = context;
mIsoDep = isoDep;
public CardProtocol(NfcReader reader, TangemCard card, Notifications notifications) {
mIsoDep = reader;
mNotifications = notifications;
if (card != null)
{
@ -164,7 +157,7 @@ public class CardProtocol {
mCard = card;
}else{
mPIN = null;
mCard = new TangemCard(Util.byteArrayToHexString(mIsoDep.getTag().getId()));
mCard = new TangemCard(Util.byteArrayToHexString(mIsoDep.getId()));
}
}
@ -177,6 +170,19 @@ public class CardProtocol {
}
}
/**
* Base exception class for exceptions on card reading
*/
public static class TangemException_TagLost extends Exception {
public TangemException_TagLost() {
super("Tag lost");
}
public TangemException_TagLost(String message) {
super(message);
}
}
/**
* Thrown on failed attempt of reading with possible wrong PIN
*/
@ -225,15 +231,15 @@ public class CardProtocol {
* @return UID byte array
*/
public byte[] GetUID() {
if (mIsoDep == null || mIsoDep.getTag() == null) return null;
return mIsoDep.getTag().getId();
if (mIsoDep == null ) return null;
return mIsoDep.getId();
}
/**
* Return ISO 14443-3 tag reading timeout
*/
public int getTimeout() {
if (mIsoDep == null || mIsoDep.getTag() == null) return 60000;
if (mIsoDep == null ) return 60000;
return mIsoDep.getTimeout();
}
@ -299,7 +305,7 @@ public class CardProtocol {
try {
if (mIsoDep == null) {
throw new TagLostException();
throw new TangemException_TagLost();
}
byte[] cmdBytes = cmdApdu.toBytes();
String cmdStr = CommandApdu.toString(cmdBytes, cmdApdu.getLc());
@ -353,7 +359,7 @@ public class CardProtocol {
try {
if (mIsoDep == null) {
throw new TagLostException();
throw new TangemException_TagLost();
}
//mIsoDep.setTimeout(msTimeout);
@ -933,12 +939,12 @@ public class CardProtocol {
* by Tangem. It may contains ~150.000 precalculated hashes of COS binary code segments.
* VERIFY_CODE command internally reads a segment of COS binary code beginning at Code_Page_Address and having length of [64 x Code_Page_Count] bytes.
* Then it appends Challenge to the code segment, calculates resulting hash and returns it in the response.
* The application needs to ensure that returned hash coincides with the one stored in the hash library (see {@link Firmwares}).
* The application needs to ensure that returned hash coincides with the one stored in the hash library (see {@see Firmwares}).
* @param hashAlgID - sha-256, sha-1, sha-224, sha-384, sha-512, crc-16
* @param codePageAddress - Value from 0 to ~3000, take from {@link Firmwares}
* @param codePageCount - Number of 32-byte pages to read: from 1 to 5, take from {@link Firmwares}
* @param challenge - Additional challenge value from 1 to 10, take from {@link Firmwares}
* @return digest bytes to compare with one stored in {@link Firmwares}
* @param codePageAddress - Value from 0 to ~3000, take from {@see Firmwares}
* @param codePageCount - Number of 32-byte pages to read: from 1 to 5, take from {@see Firmwares}
* @param challenge - Additional challenge value from 1 to 10, take from {@see Firmwares}
* @return digest bytes to compare with one stored in {@see Firmwares}
* @throws Exception - if something went wrong
*/
public byte[] run_VerifyCode(String hashAlgID, int codePageAddress, int codePageCount, byte[] challenge) throws Exception {
@ -1059,7 +1065,7 @@ public class CardProtocol {
bsDataToVerify.write(issuerDataCounter.Value);
}
try {
if (CardCrypto.VerifySignature(mCard.getIssuer().getPublicDataKey(), bsDataToVerify.toByteArray(), issuerDataSignature.Value)) {
if (CardCrypto.VerifySignature(mCard.getIssuerPublicDataKey(), bsDataToVerify.toByteArray(), issuerDataSignature.Value)) {
mCard.setIssuerData(issuerData.Value, issuerDataSignature.Value);
return TLVList.fromBytes(issuerData.Value);
} else {

View file

@ -0,0 +1,20 @@
package com.tangem.tangemcard.reader;
import java.io.IOException;
public interface NfcReader {
byte[] getId();
void setTimeout(int timeout)throws IOException;
int getTimeout();
byte[] transceive(byte[] data) throws IOException;
void ignoreTag() throws IOException;
void notifyReadResult(boolean success);
void connect();
}

View file

@ -0,0 +1,67 @@
package com.tangem.tangemcard.reader;
/**
* Created by dvol on 07.03.2018.
*/
public class SettingsMask {
public static final int IsReusable = 0x0001;
public static final int UseActivation = 0x0002;
public static final int ForbidPurgeWallet = 0x0004;
public static final int UseBlock = 0x0008;
public static final int AllowSwapPIN = 0x0010;
public static final int AllowSwapPIN2 = 0x0020;
public static final int UseCVC = 0x0040;
public static final int ForbidDefaultPIN = 0x0080;
public static final int UseOneCommandAtTime = 0x0100;
public static final int UseNDEF = 0x0200;
public static final int UseDynamicNDEF = 0x0400;
public static final int SmartSecurityDelay = 0x0800;
public static final int Protocol_AllowUnencrypted = 0x1000;
public static final int Protocol_AllowStaticEncryption = 0x2000;
public static final int ProtectIssuerDataAgainstReplay = 0x4000;
public static final int AllowSelectBlockchain = 0x8000;
public static final int DisablePrecomputedNDEF = 0x00010000;
public static String getDescription(int iValue) {
StringBuilder sb=new StringBuilder();
sb.append("[");
if ((iValue & SettingsMask.AllowSwapPIN) != 0) sb.append("AllowSwapPIN, ");
if ((iValue & SettingsMask.AllowSwapPIN2) != 0)
sb.append("AllowSwapPIN2, ");
if ((iValue & SettingsMask.ForbidDefaultPIN) != 0)
sb.append("ForbidDefaultPIN, ");
if ((iValue & SettingsMask.IsReusable) != 0) sb.append("IsReusable, ");
if ((iValue & SettingsMask.Protocol_AllowStaticEncryption) != 0)
sb.append("Protocol_AllowStaticEncryption, ");
if ((iValue & SettingsMask.Protocol_AllowUnencrypted) != 0)
sb.append("Protocol_AllowUnencrypted, ");
if ((iValue & SettingsMask.SmartSecurityDelay) != 0)
sb.append("SmartSecurityDelay, ");
if ((iValue & SettingsMask.UseActivation) != 0)
sb.append("UseActivation, ");
if ((iValue & SettingsMask.UseBlock) != 0) sb.append("UseBlock, ");
if ((iValue & SettingsMask.UseCVC) != 0) sb.append("UseCVC, ");
if ((iValue & SettingsMask.UseDynamicNDEF) != 0)
sb.append("UseDynamicNDEF, ");
if ((iValue & SettingsMask.UseNDEF) != 0) sb.append("UseNDEF, ");
if ((iValue & SettingsMask.UseOneCommandAtTime) != 0)
sb.append("UseOneCommandAtTime, ");
if ((iValue & SettingsMask.ProtectIssuerDataAgainstReplay) != 0)
sb.append("ProtectIssuerDataAgainstReplay, ");
if ((iValue & SettingsMask.ForbidPurgeWallet) != 0) sb.append("ForbidPurgeWallet, ");
if ((iValue & SettingsMask.AllowSelectBlockchain) != 0) sb.append("AllowSelectBlockchain, ");
if ((iValue & SettingsMask.DisablePrecomputedNDEF) != 0) sb.append("DisablePrecomputedNDEF, ");
if (sb.length() > 1) sb.delete(sb.length() - 2, sb.length());
sb.append("]");
return sb.toString();
}
}

View file

@ -215,34 +215,7 @@ public class TLV {
if( Value!=null ) {
try {
int iValue = Util.byteArrayToInt(Value);
sb.append("[");
if ((iValue & SettingsMask.AllowSwapPIN) != 0) sb.append("AllowSwapPIN, ");
if ((iValue & SettingsMask.AllowSwapPIN2) != 0)
sb.append("AllowSwapPIN2, ");
if ((iValue & SettingsMask.ForbidDefaultPIN) != 0)
sb.append("ForbidDefaultPIN, ");
if ((iValue & SettingsMask.IsReusable) != 0) sb.append("IsReusable, ");
if ((iValue & SettingsMask.Protocol_AllowStaticEncryption) != 0)
sb.append("Protocol_AllowStaticEncryption, ");
if ((iValue & SettingsMask.Protocol_AllowUnencrypted) != 0)
sb.append("Protocol_AllowUnencrypted, ");
if ((iValue & SettingsMask.SmartSecurityDelay) != 0)
sb.append("SmartSecurityDelay, ");
if ((iValue & SettingsMask.UseActivation) != 0)
sb.append("UseActivation, ");
if ((iValue & SettingsMask.UseBlock) != 0) sb.append("UseBlock, ");
if ((iValue & SettingsMask.UseCVC) != 0) sb.append("UseCVC, ");
if ((iValue & SettingsMask.UseDynamicNDEF) != 0)
sb.append("UseDynamicNDEF, ");
if ((iValue & SettingsMask.UseNDEF) != 0) sb.append("UseNDEF, ");
if ((iValue & SettingsMask.UseOneCommandAtTime) != 0)
sb.append("UseOneCommandAtTime, ");
if ((iValue & SettingsMask.ProtectIssuerDataAgainstReplay) != 0)
sb.append("ProtectIssuerDataAgainstReplay, ");
if (sb.length() > 1) sb.delete(sb.length() - 2, sb.length());
sb.append("]");
return String.format("%s[%d]: %s (%s)", tag.name(), Value.length, Util.bytesToHex(Value), sb.toString());
return String.format("%s[%d]: %s (%s)", tag.name(), Value.length, Util.bytesToHex(Value), SettingsMask.getDescription(iValue));
}
catch (Exception e)
{

View file

@ -4,8 +4,6 @@ package com.tangem.tangemcard.reader;
* Created by dvol on 23.06.2017.
*/
import android.support.annotation.NonNull;
import com.tangem.tangemcard.util.Util;
import java.io.ByteArrayInputStream;
@ -27,7 +25,7 @@ public class TLVList extends ArrayList<TLV> {
super();
}
public TLVList(@NonNull Collection<? extends TLV> c) {
public TLVList(Collection<? extends TLV> c) {
super(c);
}

View file

@ -1,19 +1,18 @@
package com.tangem.tangemcard.tasks;
import android.content.Context;
import android.nfc.tech.IsoDep;
import android.util.Log;
import com.tangem.tangemcard.data.external.CardDataSubstitutionProvider;
import com.tangem.tangemcard.data.external.PINsProvider;
import com.tangem.tangemcard.reader.CardProtocol;
import com.tangem.tangemcard.reader.NfcManager;
import com.tangem.tangemcard.data.local.PINStorage;
import com.tangem.tangemcard.data.TangemCard;
import com.tangem.tangemcard.reader.NfcReader;
import com.tangem.tangemcard.util.Log;
public class CreateNewWalletTask extends CustomReadCardTask {
public static final String TAG = CreateNewWalletTask.class.getSimpleName();
public CreateNewWalletTask(Context context, TangemCard card, NfcManager nfcManager, IsoDep isoDep, CardProtocol.Notifications notifications) {
super(context, card, nfcManager, isoDep, notifications);
public CreateNewWalletTask(TangemCard card, NfcReader reader, CardDataSubstitutionProvider cardDataSubstitutionProvider, PINsProvider pinsProvider, CardProtocol.Notifications notifications) {
super(card, reader, cardDataSubstitutionProvider, pinsProvider, notifications);
}
@Override
@ -25,7 +24,7 @@ public class CreateNewWalletTask extends CustomReadCardTask {
mNotifications.onReadProgress(protocol, 30);
if (isCancelled) return;
protocol.run_CreateWallet(PINStorage.getPIN2());
protocol.run_CreateWallet(pinsProvider.getPIN2());
mNotifications.onReadProgress(protocol, 60);
if (isCancelled) return;

View file

@ -1,19 +1,15 @@
package com.tangem.tangemcard.tasks;
import android.content.Context;
import android.nfc.tech.IsoDep;
import android.util.Log;
import com.tangem.tangemcard.data.Issuer;
import com.tangem.tangemcard.data.local.LocalStorage;
import com.tangem.tangemcard.data.external.CardDataSubstitutionProvider;
import com.tangem.tangemcard.data.Manufacturer;
import com.tangem.tangemcard.data.local.PINStorage;
import com.tangem.tangemcard.data.external.PINsProvider;
import com.tangem.tangemcard.data.TangemCard;
import com.tangem.tangemcard.reader.CardProtocol;
import com.tangem.tangemcard.reader.NfcManager;
import com.tangem.tangemcard.reader.NfcReader;
import com.tangem.tangemcard.reader.TLV;
import com.tangem.tangemcard.reader.TLVException;
import com.tangem.tangemcard.reader.TLVList;
import com.tangem.tangemcard.util.Log;
import com.tangem.tangemcard.util.Util;
import org.spongycastle.jce.ECNamedCurveTable;
@ -30,12 +26,12 @@ import java.util.Calendar;
public class CustomReadCardTask extends Thread {
public static final String TAG = CustomReadCardTask.class.getSimpleName();
protected IsoDep mIsoDep;
protected NfcReader mIsoDep;
protected CardProtocol.Notifications mNotifications;
protected boolean isCancelled = false;
protected Context mContext;
protected NfcManager mNfcManager;
protected TangemCard mCard ;
CardDataSubstitutionProvider localStorage;
PINsProvider pinsProvider;
CardProtocol protocol;
// this fields are static to optimize process when need enter pin and scan card again
@ -49,11 +45,11 @@ public class CustomReadCardTask extends Thread {
lastRead_UnsuccessfullPINs.clear();
}
public CustomReadCardTask(Context context, TangemCard card, NfcManager nfcManager, IsoDep isoDep, CardProtocol.Notifications notifications) {
mContext = context;
mIsoDep = isoDep;
public CustomReadCardTask(TangemCard card, NfcReader reader, CardDataSubstitutionProvider cardDataSubstitutionProvider, PINsProvider pinsProvider, CardProtocol.Notifications notifications) {
mIsoDep = reader;
mNotifications = notifications;
mNfcManager = nfcManager;
localStorage= cardDataSubstitutionProvider;
this.pinsProvider=pinsProvider;
mCard=card;
}
@ -174,6 +170,7 @@ public class CustomReadCardTask extends Thread {
try {
if (mCard.getFirmwareVersion().compareTo("1.05") < 0) {
// In FW ver 1.05, the issuer has one key pair used as both DataKey and TransactionKey, see [1] 3.3.1 and [1] 3.3.2
//mCard.setIssuer(tlvCardData.getTLV(TLV.Tag.TAG_Issuer_ID).getAsString(), protocol.getReadResult().getTLV(TLV.Tag.TAG_Issuer_Transaction_PublicKey).Value);
mCard.setIssuer(tlvCardData.getTLV(TLV.Tag.TAG_Issuer_ID).getAsString(), protocol.getReadResult().getTLV(TLV.Tag.TAG_Issuer_Transaction_PublicKey).Value);
} else {
// In newer FW versions, the issuer has two different key pairs - DataKey and TransactionKey, see [1] 3.3.1 and [1] 3.3.2
@ -188,7 +185,7 @@ public class CustomReadCardTask extends Thread {
} catch (Exception ee) {
ee.printStackTrace();
Log.e(TAG, "Cannot get issuer");
mCard.setIssuer(Issuer.Unknown().getID(), null);
mCard.setIssuer("Unknown", null);
}
}
@ -201,15 +198,15 @@ public class CustomReadCardTask extends Thread {
} else if (mCard.getBatch().equals("0019")) {
mCard.setContractAddress("0x0c056b0cda0763cc14b8b2d6c02465c91e33ec72");
} else {
LocalStorage localStorage = new LocalStorage(mContext);
localStorage.applySubstitution(mCard);
//CardDataSubstitutionProvider localStorage = new CardDataSubstitutionProvider(mContext);
if( localStorage!=null ) localStorage.applySubstitution(mCard);
}
} catch (Exception e) {
Log.e(TAG, "Can't apply card data substitution");
e.printStackTrace();
}
mCard.setBlockchainIDFromCard(tlvCardData.getTLV(TLV.Tag.TAG_Blockchain_ID).getAsString());
mCard.setBlockchainID(tlvCardData.getTLV(TLV.Tag.TAG_Blockchain_ID).getAsString());
try {
mCard.setSettingsMask(protocol.getReadResult().getTagAsInt(TLV.Tag.TAG_SettingsMask));
@ -279,7 +276,7 @@ public class CustomReadCardTask extends Thread {
public void run_FirstTimeRead() throws Exception {
byte[] UID = mIsoDep.getTag().getId();
byte[] UID = mIsoDep.getId();
String sUID = Util.byteArrayToHexString(UID);
if (!lastRead_UID.equals(sUID)) {
resetLastReadInfo();
@ -289,7 +286,7 @@ public class CustomReadCardTask extends Thread {
if (isCancelled) return;
protocol.setPIN(PINStorage.getDefaultPIN());
protocol.setPIN(CardProtocol.DefaultPIN);
protocol.clearReadResult();
if (lastRead_Encryption == null) {
@ -303,7 +300,7 @@ public class CustomReadCardTask extends Thread {
if (protocol.haveReadResult()) {
//already have read result (obtained while get supported encryption), only read issuer data and define offline balance
parseReadResult();
PINStorage.setLastUsedPIN(protocol.getCard().getPIN());
pinsProvider.setLastUsedPIN(protocol.getCard().getPIN());
} else {
//don't have read result - may be don't get supported encryption on this try, need encryption or need another PIN
if (lastRead_Encryption == null) {
@ -311,12 +308,12 @@ public class CustomReadCardTask extends Thread {
lastRead_Encryption = protocol.getCard().encryptionMode;
if (protocol.getCard().encryptionMode == TangemCard.EncryptionMode.None) {
// default pin not accepted
lastRead_UnsuccessfullPINs.add(PINStorage.getDefaultPIN());
lastRead_UnsuccessfullPINs.add(CardProtocol.DefaultPIN);
}
}
boolean pinFound = false;
for (String PIN : PINStorage.getPINs()) {
for (String PIN : pinsProvider.getPINs()) {
Log.e(TAG, "PIN: " + PIN);
boolean skipPin = false;
@ -341,7 +338,7 @@ public class CustomReadCardTask extends Thread {
// After first successful read, data will be parsed into TangemCard object
parseReadResult();
PINStorage.setLastUsedPIN(PIN);
pinsProvider.setLastUsedPIN(PIN);
pinFound = true;
protocol.getCard().setPIN(PIN);
break;
@ -365,7 +362,7 @@ public class CustomReadCardTask extends Thread {
String PIN = mCard.getPIN();
protocol.setPIN(PIN);
protocol.run_Read();
PINStorage.setLastUsedPIN(PIN);
pinsProvider.setLastUsedPIN(PIN);
if (!Arrays.equals(mCard.getCID(),protocol.getReadResult().getTLV(TLV.Tag.TAG_CardID).Value)) {
throw new CardProtocol.TangemException("Card must be the same. Reading attempt on different card!");
}
@ -388,13 +385,10 @@ public class CustomReadCardTask extends Thread {
// for Samsung's bugs -
// Workaround for the Samsung Galaxy S5 (since the
// first connection always hangs on transceive).
int timeout = mIsoDep.getTimeout();
mIsoDep.connect();
mIsoDep.close();
mIsoDep.connect();
mIsoDep.setTimeout(timeout);
try {
protocol = new CardProtocol(mContext, mIsoDep, mCard, mNotifications);
protocol = new CardProtocol(mIsoDep, mCard, mNotifications);
mNotifications.onReadStart(protocol);
try {
Log.i(TAG, String.format("[-- Start task -- %s --]", getClass().getSimpleName()));
@ -416,11 +410,11 @@ public class CustomReadCardTask extends Thread {
mNotifications.onReadFinish(protocol);
}
} finally {
mNfcManager.ignoreTag(mIsoDep.getTag());
mIsoDep.ignoreTag();
}
} catch (Exception e) {
e.printStackTrace();
mNfcManager.notifyReadResult(false);
mIsoDep.notifyReadResult(false);
}
}

Some files were not shown because too many files have changed in this diff Show more