diff --git a/app/src/main/java/com/utsmm/kbz/ui/kpay/QRTransactionFragment.java b/app/src/main/java/com/utsmm/kbz/ui/kpay/QRTransactionFragment.java index 9e9f48c..e5326fc 100644 --- a/app/src/main/java/com/utsmm/kbz/ui/kpay/QRTransactionFragment.java +++ b/app/src/main/java/com/utsmm/kbz/ui/kpay/QRTransactionFragment.java @@ -194,7 +194,8 @@ public class QRTransactionFragment extends DataBindingFragment implements DataBi } private void setUpCountDown() { - setupTimeout(10, new TimeoutCallback() { + int totalTime = intervalInSec * totalCount; + setupTimeout(totalTime, new TimeoutCallback() { @Override public void onTrick(long trickTime) { sharedViewModel.countDownTxt.setValue((trickTime / 1000)+""); diff --git a/app/src/main/java/com/utsmm/kbz/util/DownloadUtil.java b/app/src/main/java/com/utsmm/kbz/util/DownloadUtil.java index 299b33a..188afa7 100644 --- a/app/src/main/java/com/utsmm/kbz/util/DownloadUtil.java +++ b/app/src/main/java/com/utsmm/kbz/util/DownloadUtil.java @@ -120,7 +120,7 @@ public class DownloadUtil { case "application/octet-stream": return ".pem"; case "application/x-pkcs12": - return ".p12"; + return ".pkcs12"; default: return ""; } diff --git a/app/src/main/java/com/utsmm/kbz/util/tms/TMSSetupsImpl.java b/app/src/main/java/com/utsmm/kbz/util/tms/TMSSetupsImpl.java index 1a81e01..1abe0bf 100644 --- a/app/src/main/java/com/utsmm/kbz/util/tms/TMSSetupsImpl.java +++ b/app/src/main/java/com/utsmm/kbz/util/tms/TMSSetupsImpl.java @@ -215,7 +215,6 @@ public class TMSSetupsImpl implements TMSSetups{ // SystemParamsOperation.getInstance().setSecHostCurrency(currencyTextToCode(siriusHost.getCurrency())); // } } - if (siriusHost.getShortCode().isEmpty()) { SystemParamsOperation.getInstance().setShortCode(""); } @@ -608,8 +607,18 @@ public class TMSSetupsImpl implements TMSSetups{ } else if (TextUtils.equals(name, "tpdu_value")){ SystemParamsOperation.getInstance().setTpduValue(data); } else if (TextUtils.equals(name, "certificate_file")){ + if (TextUtils.isEmpty(data)) { + LogUtil.e(TAG, "certificate_file value NULL from TMS"); + continue; + } + String tmsAddress = SystemParamsOperation.getInstance().getTmsAddress(); - String url = tmsAddress+"/file/download?filePath="+data; + if (TextUtils.isEmpty(tmsAddress)) { + LogUtil.e(TAG, "TMS address is NULL — cannot download certificate"); + continue; // or return; + } +// String url = tmsAddress+"/file/download?filePath="+data; + String url = tmsAddress+"/api/v1/file/download?filePath="+data; //for local DownloadUtil.downloadCertificateRx(url, "certificate_file", path -> { if(path != null){ SystemParamsOperation.getInstance().setCertFilePath(path); @@ -618,6 +627,30 @@ public class TMSSetupsImpl implements TMSSetups{ LogUtil.e(TAG, "Failed to download certificate file"); } }); + } else if (TextUtils.equals(name, "certificate_client")){ + if (TextUtils.isEmpty(data)) { + LogUtil.e(TAG, "certificate_file value NULL from TMS"); + continue; + } + + String tmsAddress = SystemParamsOperation.getInstance().getTmsAddress(); + if (TextUtils.isEmpty(tmsAddress)) { + LogUtil.e(TAG, "TMS address is NULL — cannot download certificate"); + continue; // or return; + } +// String url = tmsAddress+"/file/download?filePath="+data; + String url = tmsAddress+"/api/v1/file/download?filePath="+data; //for local + DownloadUtil.downloadCertificateRx(url, "certificate_client", path -> { + if(path != null){ + SystemParamsOperation.getInstance().setCertClientFilePath(path); + LogUtil.d(TAG, "Cert client file path saved in SystemParams => " + path); + }else{ + LogUtil.e(TAG, "Failed to download certificate client file"); + } + }); + } + else if (TextUtils.equals(name, "certificate_password")) { + SystemParamsOperation.getInstance().setCertificatePassword(data); } } diff --git a/baselib/src/main/java/com/utsmyanmar/baselib/di/NetworkModule.java b/baselib/src/main/java/com/utsmyanmar/baselib/di/NetworkModule.java index 28cfc86..94b7c30 100644 --- a/baselib/src/main/java/com/utsmyanmar/baselib/di/NetworkModule.java +++ b/baselib/src/main/java/com/utsmyanmar/baselib/di/NetworkModule.java @@ -1,6 +1,8 @@ package com.utsmyanmar.baselib.di; import android.content.Context; +import android.text.TextUtils; +import android.util.Log; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.jetbrains.annotations.NotNull; @@ -20,6 +22,7 @@ import com.utsmyanmar.paylibs.Constant; import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation; import com.utsmyanmar.baselib.R; +import java.io.FileInputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -46,6 +49,7 @@ import javax.net.ssl.X509TrustManager; import dagger.Module; import dagger.Provides; +import dagger.Reusable; import dagger.hilt.InstallIn; import dagger.hilt.android.qualifiers.ApplicationContext; import dagger.hilt.components.SingletonComponent; @@ -301,85 +305,175 @@ public class NetworkModule { } - @Provides - @Singleton - @KPayRefundRetrofit - public Retrofit provideKPayRefundRetrofit(@ApplicationContext Context context) { - char[] password = "test123".toCharArray(); +// @Provides +// @Singleton +// @KPayRefundRetrofit +// public Retrofit provideKPayRefundRetrofit(@ApplicationContext Context context) { +// char[] password = "test123".toCharArray(); +// +// try { +// +// if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { +// Security.addProvider(new BouncyCastleProvider()); +// } +// // Client keystore +// KeyStore clientKeyStore = KeyStore.getInstance("PKCS12",new BouncyCastleProvider()); +// InputStream clientStream = context.getResources().openRawResource(R.raw.client); +// clientKeyStore.load(clientStream, password); +// clientStream.close(); +// +// KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); +// kmf.init(clientKeyStore, password); +// KeyManager[] keyManagers = kmf.getKeyManagers(); +// +// InputStream caInput = context.getResources().openRawResource(R.raw.certi); +// CertificateFactory cf = CertificateFactory.getInstance("X.509"); +// Certificate ca = cf.generateCertificate(caInput); +// +// KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); +// keyStore.load(null, null); +// keyStore.setCertificateEntry("ca", ca); +// +// TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); +// tmf.init(keyStore); +// TrustManager[] trustManagers = tmf.getTrustManagers(); +// +// X509TrustManager x509TrustManager = null; +// for (TrustManager tm : trustManagers) { +// if (tm instanceof X509TrustManager) { +// x509TrustManager = (X509TrustManager) tm; +// break; +// } +// } +// +// SSLContext sslContext = SSLContext.getInstance("TLS"); +// sslContext.init(kmf.getKeyManagers(), new TrustManager[]{x509TrustManager}, null); +// +// HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); +// loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); +// +// OkHttpClient okHttp = new OkHttpClient.Builder() +// .sslSocketFactory(sslContext.getSocketFactory(), x509TrustManager) +// .addInterceptor(loggingInterceptor) +// .hostnameVerifier(new HostnameVerifier() { +// @Override +// public boolean verify(String hostname, SSLSession session) { +// return true; +// } +// }) +// .build(); +// +// return new Retrofit.Builder() +// .baseUrl(Refund_Base_Url) +// .client(okHttp) +// .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) +// .addConverterFactory(GsonConverterFactory.create()) +// .build(); +// +// } catch (Exception e) { +// e.printStackTrace(); +// +// OkHttpClient okHttp = new OkHttpClient(); +// return new Retrofit.Builder() +// .baseUrl(Refund_Base_Url) +// .client(okHttp) +// .addConverterFactory(GsonConverterFactory.create()) +// .build(); +// +//// throw new RuntimeException("Failed to create Retrofit instance", e); +// } +// +// } - try { +@Provides +@Reusable +@KPayRefundRetrofit +public Retrofit provideKPayRefundRetrofit(@ApplicationContext Context context) { - if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { - Security.addProvider(new BouncyCastleProvider()); - } - // Client keystore - KeyStore clientKeyStore = KeyStore.getInstance("PKCS12",new BouncyCastleProvider()); - InputStream clientStream = context.getResources().openRawResource(R.raw.client); - clientKeyStore.load(clientStream, password); - clientStream.close(); +// char[] password = "test123".toCharArray(); - KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - kmf.init(clientKeyStore, password); - KeyManager[] keyManagers = kmf.getKeyManagers(); + String pass = SystemParamsOperation.getInstance().getCertificatePassword(); + if (TextUtils.isEmpty(pass)) { + LogUtil.e("RefundCert", "Certificate password is missing!"); + pass = "test123"; + } + LogUtil.d("kmk", "pass => "+pass); - InputStream caInput = context.getResources().openRawResource(R.raw.certi); - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - Certificate ca = cf.generateCertificate(caInput); + char[] password = pass.toCharArray(); - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - keyStore.load(null, null); - keyStore.setCertificateEntry("ca", ca); + try { + // Required for PKCS12 loading on Android + Security.removeProvider("BC"); + Security.addProvider(new BouncyCastleProvider()); - TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - tmf.init(keyStore); - TrustManager[] trustManagers = tmf.getTrustManagers(); + String clientPath = SystemParamsOperation.getInstance().getCertClientFilePath(); + LogUtil.d("kmk", "client path => " + clientPath); + String caPath = SystemParamsOperation.getInstance().getCertFilePath(); + LogUtil.d("kmk", "ca path => " + caPath); - X509TrustManager x509TrustManager = null; - for (TrustManager tm : trustManagers) { - if (tm instanceof X509TrustManager) { - x509TrustManager = (X509TrustManager) tm; - break; - } - } - - SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(kmf.getKeyManagers(), new TrustManager[]{x509TrustManager}, null); - - HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); - loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); - - OkHttpClient okHttp = new OkHttpClient.Builder() - .sslSocketFactory(sslContext.getSocketFactory(), x509TrustManager) - .addInterceptor(loggingInterceptor) - .hostnameVerifier(new HostnameVerifier() { - @Override - public boolean verify(String hostname, SSLSession session) { - return true; - } - }) - .build(); - - return new Retrofit.Builder() - .baseUrl(Refund_Base_Url) - .client(okHttp) - .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) - .addConverterFactory(GsonConverterFactory.create()) - .build(); - - } catch (Exception e) { - e.printStackTrace(); - - OkHttpClient okHttp = new OkHttpClient(); - return new Retrofit.Builder() - .baseUrl(Refund_Base_Url) - .client(okHttp) - .addConverterFactory(GsonConverterFactory.create()) - .build(); - -// throw new RuntimeException("Failed to create Retrofit instance", e); + if (TextUtils.isEmpty(clientPath) || TextUtils.isEmpty(caPath)) { + LogUtil.e("RefundCert", "Certificate files missing."); + throw new RuntimeException("No certificate files found."); } + // Load PKCS12 file + KeyStore clientKeyStore = KeyStore.getInstance("PKCS12", "BC"); + FileInputStream clientStream = new FileInputStream(clientPath); + clientKeyStore.load(clientStream, password); + clientStream.close(); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(clientKeyStore, password); + + // Load CA certificate from .crt + FileInputStream caStream = new FileInputStream(caPath); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + Certificate ca = cf.generateCertificate(caStream); + caStream.close(); + + // Create trust store + KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + trustStore.load(null); + trustStore.setCertificateEntry("ca", ca); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(trustStore); + + X509TrustManager x509TrustManager = (X509TrustManager) tmf.getTrustManagers()[0]; + + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(kmf.getKeyManagers(), new TrustManager[]{x509TrustManager}, null); + + HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); + interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); + + OkHttpClient okHttp = new OkHttpClient.Builder() + .sslSocketFactory(sslContext.getSocketFactory(), x509TrustManager) + .addInterceptor(interceptor) + .hostnameVerifier((h, s) -> true) + .build(); + + return new Retrofit.Builder() + .baseUrl(Refund_Base_Url) + .client(okHttp) + .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) + .addConverterFactory(GsonConverterFactory.create()) + .build(); + + } catch (Exception e) { + LogUtil.e("RefundSSL", "Error: " + e.getMessage()); + e.printStackTrace(); + + // Provide fallback Retrofit to avoid crash, but no SSL + return new Retrofit.Builder() + .baseUrl(Refund_Base_Url) + .client(new OkHttpClient()) + .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) + .addConverterFactory(GsonConverterFactory.create()) + .build(); } +} + @Provides @Singleton diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/core_utils/SystemParamsOperation.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/core_utils/SystemParamsOperation.java index 4da9cc1..0dd8522 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/core_utils/SystemParamsOperation.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/core_utils/SystemParamsOperation.java @@ -1627,4 +1627,26 @@ public class SystemParamsOperation { SystemParamsSettings params = getSystemParamsSettings(); return params.getCertFilePath(); } + + public void setCertClientFilePath(String path) { + SystemParamsSettings params = getSystemParamsSettings(); + params.setCertClientFilePath(path); + saveSystemParamsSettings(params); + } + + public String getCertClientFilePath(){ + SystemParamsSettings params = getSystemParamsSettings(); + return params.getCertClientFilePath(); + } + + public void setCertificatePassword(String value) { + SystemParamsSettings params = getSystemParamsSettings(); + params.setCertificatePassword(value); + saveSystemParamsSettings(params); + } + + public String getCertificatePassword(){ + SystemParamsSettings params = getSystemParamsSettings(); + return params.getCertificatePassword(); + } } \ No newline at end of file diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/core_utils/SystemParamsSettings.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/core_utils/SystemParamsSettings.java index 5b10bef..67b2c33 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/core_utils/SystemParamsSettings.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/core_utils/SystemParamsSettings.java @@ -243,8 +243,10 @@ public class SystemParamsSettings implements Serializable { private boolean qrPartialRefundEnable = false; private boolean qrDecimalEnable = false; - private boolean qrRefundEnable = false; + private boolean qrRefundEnable = true; private String certFilePath = ""; + private String certClientFilePath = ""; + private String certificatePassword = ""; public boolean isQrPartialRefundEnable(){ return qrPartialRefundEnable; @@ -980,6 +982,22 @@ public class SystemParamsSettings implements Serializable { return certFilePath; } + public String getCertClientFilePath() { + return certClientFilePath; + } + + public void setCertClientFilePath(String path){ + this.certClientFilePath = path; + } + + public void setCertificatePassword(String certificatePassword) { + this.certificatePassword = certificatePassword; + } + + public String getCertificatePassword() { + return certificatePassword; + } + /* // 流水号起始 private String serialNum = Configs.getInstance().SERIAL_NUM(); // 批次号起始