Updated on 2026-08-14

This commit is contained in:
Tangem 2018-07-18 12:14:21 +03:00
parent ff6efa8f37
commit 6cf2cd2afb
13 changed files with 239 additions and 111 deletions

Binary file not shown.

View file

@ -50,8 +50,8 @@ dependencies {
implementation 'com.android.support:cardview-v7:27.1.1'
implementation 'com.android.support:support-v4:27.1.1'
implementation 'com.google.zxing:core:3.3.2'
implementation 'com.google.dagger:dagger:2.13'
annotationProcessor 'com.google.dagger:dagger-compiler:2.13'
// implementation 'com.google.dagger:dagger:2.13'
// annotationProcessor 'com.google.dagger:dagger-compiler:2.13'
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.6'
@ -61,7 +61,8 @@ dependencies {
implementation 'me.dm7.barcodescanner:zxing:1.9.8'
implementation 'info.hoang8f:android-segmented:1.0.6'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.android.volley:volley:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
// androidTestImplementation 'com.android.support.test:runner:1.0.2'
// androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

View file

@ -2,9 +2,21 @@ package com.tangem;
import android.app.Application;
import android.support.v7.app.AppCompatDelegate;
import android.text.TextUtils;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.VolleyLog;
import com.android.volley.toolbox.Volley;
public class AppController extends Application {
private static final String TAG = "." + AppController.class.getSimpleName();
public static final String TAG = "fragment." + AppController.class.getSimpleName();
/**
* Global request queue for Volley
*/
private RequestQueue mRequestQueue;
/**
* A singleton instance of the application class for easy access in other places
@ -22,20 +34,64 @@ public class AppController extends Application {
@Override
public void onCreate() {
super.onCreate();
// init the singleton
// initialize the singleton
sInstance = this;
}
/**
* @return singleton instance
* @return SeoPult singleton instance
*/
public static synchronized AppController getInstance() {
return sInstance;
}
@Override
public void onTerminate() {
super.onTerminate();
/**
* @return The Volley Request queue, the queue will be created if it is null
*/
public RequestQueue getRequestQueue() {
// lazy initialize the request queue, the queue instance will be created when it is accessed for the first time
if (mRequestQueue == null)
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
return mRequestQueue;
}
/**
* Adds the specified request to the global queue, if tag is specified
* then it is used else Default TAG is used.
*
* @param req
* @param tag
*/
public <T> void addToRequestQueue(Request<T> req, String tag) {
// set the default tag if tag is empty
req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
VolleyLog.d("Adding request to queue: %s", req.getUrl());
getRequestQueue().add(req);
}
/**
* Adds the specified request to the global queue using the Default TAG.
*
* @param req
*/
public <T> void addToRequestQueue(Request<T> req) {
// set the default tag if tag is empty
req.setTag(TAG);
getRequestQueue().add(req);
}
/**
* Cancels all pending requests by the specified TAG, it is important
* to specify a TAG so that the pending/ongoing requests can be cancelled.
*
* @param tag
*/
public void cancelPendingRequests(Object tag) {
if (mRequestQueue != null) {
mRequestQueue.cancelAll(tag);
}
}
}

View file

@ -1,15 +0,0 @@
package com.tangem.DI;
import com.tangem.AppController;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
void inject(AppController appController);
}

View file

@ -1,8 +0,0 @@
package com.tangem.DI;
import dagger.Module;
@Module
public class AppModule {
}

View file

@ -1,10 +0,0 @@
package com.tangem.DI;
import com.tangem.domain.cardReader.NfcManager;
//@Component
public interface NfcManagerComponent {
// NfcManager getNfcManager(Activity activity, NfcAdapter.ReaderCallback readerCallback);
NfcManager getNfcManager();
}

View file

@ -0,0 +1,29 @@
package com.tangem.data.network;
import java.util.HashMap;
import java.util.Map;
public class Server {
public static Map<String, String> getHeader() {
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "application/json");
return headers;
}
public static class API {
private static final String URL_TANGEM = ServerURL.API_TANGEM;
public static class Method {
/**
* https://tangem-webapp.appspot.com/
*/
public static final String INFO_VERIFY = URL_TANGEM + "info/version";
public static final String CARD_VERIFY = URL_TANGEM + "card/verify";
public static final String CARD_VALIDATE = URL_TANGEM + "card/validate";
public static final String CARD_ACTIVATE = URL_TANGEM + "card/activate";
}
}
}

View file

@ -0,0 +1,11 @@
package com.tangem.data.network;
public class ServerURL {
public static final String API_TANGEM = "https://tangem-webapp.appspot.com/";
}

View file

@ -0,0 +1,54 @@
package com.tangem.data.network
import android.content.Context
import android.content.Intent
import android.support.v7.app.AlertDialog
import com.android.volley.AuthFailureError
import com.android.volley.DefaultRetryPolicy
import com.android.volley.Request
import com.android.volley.toolbox.StringRequest
import com.google.gson.GsonBuilder
import com.google.gson.JsonParser
import com.tangem.AppController
import com.tangem.wallet.R
class VolleyHelper {
fun doRequest(context: Context, url: String, params: Map<String, String>) {
val stringRequest = object : StringRequest(Request.Method.POST, url,
{ response ->
val data = GsonBuilder().setPrettyPrinting().create().toJson(JsonParser().parse(response))
val builder = AlertDialog.Builder(context)
builder.setTitle("sxsx")
.setMessage(data)
.setPositiveButton(R.string.ok, null)
.setNeutralButton(R.string.send) { _, _ ->
val intent = Intent(Intent.ACTION_SEND)
intent.type = "text/html"
intent.putExtra(Intent.EXTRA_EMAIL, arrayOf("digest2003@mail.ru"))
intent.putExtra(Intent.EXTRA_SUBJECT, url)
intent.putExtra(Intent.EXTRA_TEXT, data)
context.startActivity(Intent.createChooser(intent, "Send gson"))
}
val alert = builder.create()
alert.show()
},
{ error -> val networkResponse = error.networkResponse }) {
@Throws(AuthFailureError::class)
override fun getHeaders(): Map<String, String> {
return Server.getHeader()
}
@Throws(AuthFailureError::class)
override fun getParams(): Map<String, String> {
return params
}
}
stringRequest.retryPolicy = DefaultRetryPolicy(60000, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT)
AppController.getInstance().addToRequestQueue(stringRequest)
}
}

View file

@ -22,20 +22,19 @@ import java.util.Locale;
public class VerificationServerProtocol {
public static class Request
{
public Request(CustomCommand command, Class answerClass)
{
this.command=command;
this.answerClass=answerClass;
public static class Request {
public Request(CustomCommand command, Class answerClass) {
this.command = command;
this.answerClass = answerClass;
}
public String error;
public CustomCommand command;
public CustomAnswer answer;
public Type answerClass;
public void doPost(String hostURL) throws IOException {
URL url = new URL(hostURL+"/"+command.getURL());
URL url = new URL(hostURL + "/" + command.getURL());
URLConnection con = url.openConnection();
HttpURLConnection http = (HttpURLConnection) con;
try {
@ -60,8 +59,7 @@ public class VerificationServerProtocol {
answer = getGson().fromJson(br, answerClass);
}
}
}
finally {
} finally {
http.disconnect();
}
}
@ -70,8 +68,7 @@ public class VerificationServerProtocol {
static abstract class CustomCommand {
public abstract String getURL();
public byte[] toBytes()
{
public byte[] toBytes() {
return getGson().toJson(this).getBytes(StandardCharsets.UTF_8);
}
@ -121,15 +118,14 @@ public class VerificationServerProtocol {
public ResultItem[] results;
}
public static Request prepare(TangemCard card)
{
Command c=new Command();
c.requests=new RequestItem[1];
c.requests[0]=new RequestItem();
c.requests[0].CID=Util.bytesToHex(card.getCID());
c.requests[0].publicKey=Util.bytesToHex(card.getCardPublicKey());
public static Request prepare(TangemCard card) {
Command c = new Command();
c.requests = new RequestItem[1];
c.requests[0] = new RequestItem();
c.requests[0].CID = Util.bytesToHex(card.getCID());
c.requests[0].publicKey = Util.bytesToHex(card.getCardPublicKey());
return new Request(c,Answer.class);
return new Request(c, Answer.class);
}
}
@ -154,6 +150,7 @@ public class VerificationServerProtocol {
public ResultItem(RequestItem request) {
CID = request.CID;
}
public String error;
public String CID;
public Integer previousCounter;
@ -164,14 +161,13 @@ public class VerificationServerProtocol {
public ResultItem[] results;
}
public Request prepare(TangemCard card, int ValidationCounter, byte[] ValidationSignature)
{
Command c=new Command();
c.requests=new RequestItem[1];
c.requests[0].CID= Util.bytesToHex(card.getCID());
c.requests[0].counter=ValidationCounter;
c.requests[0].signature=Util.bytesToHex(ValidationSignature);
return new Request(new Command(),Answer.class);
public Request prepare(TangemCard card, int ValidationCounter, byte[] ValidationSignature) {
Command c = new Command();
c.requests = new RequestItem[1];
c.requests[0].CID = Util.bytesToHex(card.getCID());
c.requests[0].counter = ValidationCounter;
c.requests[0].signature = Util.bytesToHex(ValidationSignature);
return new Request(new Command(), Answer.class);
}
}

View file

@ -8,35 +8,34 @@ import java.util.ArrayList;
import java.util.List;
public class VerificationServerTask extends AsyncTask<VerificationServerProtocol.Request, Void, List<VerificationServerProtocol.Request>> {
public static final String hostURL ="https://tangem-webapp.appspot.com";
public static final String hostURL = "https://tangem-webapp.appspot.com";
public VerificationServerTask() {
}
protected List<VerificationServerProtocol.Request> doInBackground(VerificationServerProtocol.Request... requests) {
List<VerificationServerProtocol.Request> result = new ArrayList<>();
for (int i = 0; i < requests.length; i++) {
result.add(requests[i]);
}
for (VerificationServerProtocol.Request request : result) {
try {
request.doPost(hostURL);
} catch (Exception e) {
request.error = e.getMessage();
if( request.error==null || request.error.isEmpty() )
{
request.error = e.getClass().getName();
}
}
}
return result;
}
public String getValidationNodeDescription() {
return hostURL;
}
public VerificationServerTask() {
}
protected List<VerificationServerProtocol.Request> doInBackground(VerificationServerProtocol.Request... requests) {
List<VerificationServerProtocol.Request> result = new ArrayList<>();
for (int i = 0; i < requests.length; i++) {
result.add(requests[i]);
}
for (VerificationServerProtocol.Request request : result) {
try {
request.doPost(hostURL);
} catch (Exception e) {
request.error = e.getMessage();
if (request.error == null || request.error.isEmpty()) {
request.error = e.getClass().getName();
}
}
}
return result;
}
public String getValidationNodeDescription() {
return hostURL;
}
}

View file

@ -30,6 +30,8 @@ import android.widget.TextView;
import android.widget.Toast;
import com.google.zxing.WriterException;
import com.tangem.data.network.Server;
import com.tangem.data.network.VolleyHelper;
import com.tangem.data.network.request.ElectrumRequest;
import com.tangem.data.network.request.ExchangeRequest;
import com.tangem.data.network.request.InfuraRequest;
@ -63,7 +65,9 @@ import com.tangem.util.Util;
import com.tangem.util.UtilHelper;
import com.tangem.wallet.R;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Timer;
import java.util.TimerTask;
@ -88,21 +92,23 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
public SwipeRefreshLayout mSwipeRefreshLayout;
private RelativeLayout rlProgressBar;
private TextView tvCardID, tvBalance, tvBalanceLine1, tvBalanceLine2,tvOffline, tvBalanceEquivalent, tvWallet, tvInputs, tvError, tvMessage, tvIssuer, tvBlockchain, tvValidationNode, tvHeader, tvCaution;
// private ProgressBar progressBar;
private TextView tvCardID, tvBalance, tvBalanceLine1, tvBalanceLine2, tvOffline, tvBalanceEquivalent, tvWallet, tvInputs, tvError, tvMessage, tvIssuer, tvBlockchain, tvValidationNode, tvHeader, tvCaution;
// private ProgressBar progressBar;
private ImageView ivPIN, ivPIN2orSecurityDelay, ivDeveloperVersion;
private AppCompatButton btnExtract;
// public List<AsyncTask> updateTasks = new ArrayList<>();
// public List<AsyncTask> updateTasks = new ArrayList<>();
private boolean lastReadSuccess = true;
private VerifyCardTask verifyCardTask = null;
private int requestPIN2Count = 0;
private Timer timerHideErrorAndMessage = null;
private String newPIN = "", newPIN2 = "";
private CardProtocol mCardProtocol;
// private int scanTimes = 0;
// private int scanTimes = 0;
OnlineVerifyTask onlineVerifyTask;
private static final String URL_CARD_VALIDATE = Server.API.Method.CARD_VALIDATE;
public LoadedWallet() {
}
@ -122,7 +128,7 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
super.onPostExecute(requests);
// Log.i("OnlineVerifyTask", "onPostExecute[" + String.valueOf(updateTasks.size()) + "]");
// updateTasks.remove(this);
onlineVerifyTask=null;
onlineVerifyTask = null;
for (VerificationServerProtocol.Request request : requests) {
if (request.error == null) {
@ -139,10 +145,18 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
}
}
// if (updateTasks.size() == 0)
mSwipeRefreshLayout.setRefreshing(false);
mSwipeRefreshLayout.setRefreshing(false);
}
}
private void requestCardValidate() {
Map<String, String> params = new HashMap<>();
params.put("Content-Type", "application/json");
params.put("CID", Util.bytesToHex(mCard.getCID()));
params.put("publicKey", Util.bytesToHex(mCard.getCardPublicKey()));
new VolleyHelper().doRequest(getContext(), URL_CARD_VALIDATE, params);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@ -153,6 +167,8 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
mCard.LoadFromBundle(Objects.requireNonNull(getActivity().getIntent().getExtras()).getBundle(TangemCard.EXTRA_CARD));
lastTag = getActivity().getIntent().getParcelableExtra(Main.EXTRA_LAST_DISCOVERED_TAG);
// requestCardValidate();
}
@Override
@ -215,7 +231,7 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
mSwipeRefreshLayout.postDelayed(this::onRefresh, 1000);
}
if ( (mCard.isOnlineVerified()==null || !mCard.isOnlineVerified()) && onlineVerifyTask ==null) {
if ((mCard.isOnlineVerified() == null || !mCard.isOnlineVerified()) && onlineVerifyTask == null) {
onlineVerifyTask = new OnlineVerifyTask();
// updateTasks.add(onlineVerifyTask);
onlineVerifyTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, VerificationServerProtocol.Verify.prepare(mCard));
@ -508,7 +524,7 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
CoinEngine engine = CoinEngineFactory.Create(mCard.getBlockchain());
if ( (mCard.isOnlineVerified()==null || !mCard.isOnlineVerified()) && onlineVerifyTask ==null) {
if ((mCard.isOnlineVerified() == null || !mCard.isOnlineVerified()) && onlineVerifyTask == null) {
onlineVerifyTask = new OnlineVerifyTask();
// updateTasks.add(onlineVerifyTask);
onlineVerifyTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, VerificationServerProtocol.Verify.prepare(mCard));
@ -547,7 +563,7 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
String nodeAddress = Objects.requireNonNull(engine).GetNode(mCard);
int nodePort = engine.GetNodePort(mCard);
UpdateWalletInfoTask updateWalletInfoTask = new UpdateWalletInfoTask(LoadedWallet.this,nodeAddress, nodePort, data);
UpdateWalletInfoTask updateWalletInfoTask = new UpdateWalletInfoTask(LoadedWallet.this, nodeAddress, nodePort, data);
// updateTasks.add(updateWalletInfoTask);
updateWalletInfoTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, ElectrumRequest.ListUnspent(mCard.getWallet())
@ -608,7 +624,6 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
}
public Intent prepareResultIntent() {
Intent data = new Intent();
data.putExtra("UID", mCard.getUID());
@ -750,7 +765,7 @@ public class LoadedWallet extends Fragment implements SwipeRefreshLayout.OnRefre
validator.Check(mCard);
tvBalanceLine1.setText(validator.GetFirstLine());
tvBalanceLine2.setText(validator.GetSecondLine());
tvBalanceLine1.setTextColor(ContextCompat.getColor(Objects.requireNonNull(getContext()),validator.GetColor()));
tvBalanceLine1.setTextColor(ContextCompat.getColor(Objects.requireNonNull(getContext()), validator.GetColor()));
}
if (engine.HasBalanceInfo(mCard) || mCard.getOfflineBalance() == null) {

View file

@ -243,7 +243,7 @@ public class Util {
}
//This prints all non-control characters common to all parts of ISO/IEC 8859
//See EMV book 4 Annex B: Table 36: Common Character Set
//See EMV book 4 Annex B: Table 36: VolleyHelper Character Set
public static String getSafePrintChars(byte[] byteArray) {
if (byteArray == null) {
return "";