diff --git a/app/src/main/java/com/example/hpostesting/data/api/MolbioResultApi.kt b/app/src/main/java/com/example/hpostesting/data/api/MolbioResultApi.kt index dfc1468..d93fd17 100644 --- a/app/src/main/java/com/example/hpostesting/data/api/MolbioResultApi.kt +++ b/app/src/main/java/com/example/hpostesting/data/api/MolbioResultApi.kt @@ -23,6 +23,7 @@ import com.example.hpostesting.data.model.updates.CheckUpdateResponse import com.example.hpostesting.data.model.updates.DeviceUpdateRequest import okhttp3.MultipartBody import okhttp3.ResponseBody +import retrofit2.Response import retrofit2.http.Body import retrofit2.http.GET import retrofit2.http.Multipart @@ -45,7 +46,7 @@ interface MolbioResultApi { @POST("deviceService/device/getUpdate") suspend fun deviceUpdate( @Body deviceUpdateRequest: DeviceUpdateRequest, - ): ResponseBody + ): Response @GET("deviceService/device/getClientCertificate") suspend fun downloadClientCertificate( diff --git a/app/src/main/java/com/example/hpostesting/data/repository/DatabaseRepository.kt b/app/src/main/java/com/example/hpostesting/data/repository/DatabaseRepository.kt index d93bce0..35942da 100644 --- a/app/src/main/java/com/example/hpostesting/data/repository/DatabaseRepository.kt +++ b/app/src/main/java/com/example/hpostesting/data/repository/DatabaseRepository.kt @@ -93,8 +93,8 @@ class DatabaseRepository @Inject constructor( return safeApiCall { molbioResultApi.checkUpdate(checkUpdateRequest) } } - override suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): Result { - return safeApiCall { molbioResultApi.deviceUpdate(deviceUpdateRequest) } + override suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): retrofit2.Response { + return molbioResultApi.deviceUpdate(deviceUpdateRequest) } override suspend fun deviceDiagnostics(deviceDiagnosticsRequest: DeviceDiagnosticsRequest): Result { diff --git a/app/src/main/java/com/example/hpostesting/data/repository/Repository.kt b/app/src/main/java/com/example/hpostesting/data/repository/Repository.kt index c59ffbf..88f3225 100644 --- a/app/src/main/java/com/example/hpostesting/data/repository/Repository.kt +++ b/app/src/main/java/com/example/hpostesting/data/repository/Repository.kt @@ -64,7 +64,7 @@ interface Repository { suspend fun checkUpdate(checkUpdateRequest: CheckUpdateRequest): Result - suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): Result + suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): retrofit2.Response suspend fun deviceDiagnostics(deviceDiagnosticsRequest: DeviceDiagnosticsRequest): Result suspend fun downloadClientCertificate(): Result suspend fun uploadLogs(logFile: MultipartBody.Part): Result diff --git a/app/src/main/java/com/example/hpostesting/presentation/SplashActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/SplashActivity.kt index 4a5bb1a..a12d4eb 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/SplashActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/SplashActivity.kt @@ -14,6 +14,7 @@ package com.example.hpostesting.presentation import android.Manifest +import android.annotation.SuppressLint import android.content.Context import android.content.Intent import android.content.pm.PackageManager @@ -33,6 +34,7 @@ import com.example.hpostesting.util.MyUtils import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.databinding.ActivitySplashBinding +@SuppressLint("CustomSplashScreen") class SplashActivity : AppCompatActivity() { private lateinit var binding: ActivitySplashBinding @@ -64,6 +66,7 @@ class SplashActivity : AppCompatActivity() { requestPermissions() } + @SuppressLint("HardwareIds") private fun setupStaticConstants() { DataHolder.mobileUniqueId = Settings.Secure.getString( diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt index 8deb5b2..20d401e 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt @@ -35,7 +35,9 @@ import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupWithNavController import com.example.hpostesting.util.Result import com.example.hpostesting.data.constant.Constants +import com.example.hpostesting.data.constant.DataHolder import com.example.hpostesting.data.constant.LanguageManager +import com.example.hpostesting.data.model.login.LoginRequest import com.example.hpostesting.data.model.updates.DeviceUpdateRequest import com.example.hpostesting.presentation.utils.NatsManager import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel @@ -49,6 +51,7 @@ import `in`.sminnovations.hpostesting.BuildConfig import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding import java.io.File +import java.security.MessageDigest interface NatsMessageCallback { fun onMessageReceived(topic: String, message: String) @@ -106,43 +109,34 @@ class DashboardActivity : AppCompatActivity(), IDataCollector { nats.sub("server.hpos.${deviceId}.ping") nats.pub("server.hpos.${deviceId}.ping", "THIS IS A TEST MSG") - hemocubeViewModel.deviceUpdate.observe(this) { result -> - when (result) { - is Result.Success -> { - // Handle success - val apk = result.data - val file = File(getExternalFilesDir("Updates"), "update.apk") - file.setReadable(true, false) // Ensure the file is readable - apk.byteStream().use { input -> - file.outputStream().use { output -> - input.copyTo(output) - } - } - Log.d("Responsebodyformat", "Responsebodyformat: ") - installApk(file) - Log.e("ApI", "APK URL: $apk") - Toast.makeText( - this, - "${result.data}", - Toast.LENGTH_SHORT - ).show() - } + hemocubeViewModel.deviceUpdate.observe(this) { + Log.d("DashboardLogs",it.toString()) - is Result.Error -> { - result.exception.let { message -> - Toast.makeText(this, "An error occurred On Updating App: $message", Toast.LENGTH_LONG) - .show() - } - } + var apk = it + val file = File(getExternalFilesDir("Downloads"), "update.apk") + file.setReadable(true, false) - is Result.Loading -> { - } - - else -> { + // Write APK to file + apk.byteStream().use { input -> + file.outputStream().use { output -> + input.copyTo(output) } } - } + } + hemocubeViewModel.deviceUpdateheader.observe(this){ + val apkFile = File(getExternalFilesDir("Downloads"), "update.apk") + val expectedChecksum = it.get("Checksum") // Provide your expected checksum here + val algorithm = "SHA-256" // Choose the algorithm you want to use (e.g., MD5, SHA-1, SHA-256) + + val isIntegrityVerified = verifyChecksum(apkFile, expectedChecksum!!, algorithm) + if (isIntegrityVerified) { + println("APK integrity verified: The file has not been tampered with.") + installApk(apkFile) + } else { + println("APK integrity check failed: The file may have been tampered with.") + } + } val drawerLayout: DrawerLayout = binding.drawerLayout val navView: NavigationView = binding.navView @@ -175,7 +169,24 @@ class DashboardActivity : AppCompatActivity(), IDataCollector { return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() } + fun calculateChecksum(file: File, algorithm: String): String { + val digest = MessageDigest.getInstance(algorithm) + val inputStream = file.inputStream() + val buffer = ByteArray(8192) + var bytesRead = inputStream.read(buffer) + while (bytesRead != -1) { + digest.update(buffer, 0, bytesRead) + bytesRead = inputStream.read(buffer) + } + val checksumBytes = digest.digest() + return checksumBytes.joinToString("") { "%02x".format(it) } + } + // Function to verify checksum + fun verifyChecksum(file: File, expectedChecksum: String, algorithm: String): Boolean { + val actualChecksum = calculateChecksum(file, algorithm) + return actualChecksum.equals(expectedChecksum, ignoreCase = true) + } private fun installApk(file: File) { val pInfo = baseContext.packageManager.getPackageInfo(baseContext.packageName, 0) val uri: Uri = FileProvider.getUriForFile( @@ -284,4 +295,6 @@ class DashboardActivity : AppCompatActivity(), IDataCollector { "N/A" } } + + } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt index 4e02cd6..ccef187 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt @@ -374,7 +374,7 @@ class HomeFragment : Fragment() { //isTokenAvailable = true // hemoCubeViewModel.startPeriodicCheckUpdate() } - } else if (userID == "deviceIDAPI" && password == "devicePasswordAPI" && deviceId.isNotEmpty()) { + } else if (userID == "" && password == "" && deviceId.isNotEmpty()) { fetchDeviceCredentials() } else if (file.exists()) { val encryptedString = file.readText() @@ -385,6 +385,12 @@ class HomeFragment : Fragment() { userID = credentials[0] password = credentials[1] deviceId = credentials[0] + + with(sharedPreference.edit()) { + putString(Constants.DEVICE_ID_API, credentials[0]) + putString(Constants.DEVICE_PASSWORD_API, credentials[1]) + apply() + } // Toast.makeText(context, "DECRYPTED: $credentials", Toast.LENGTH_SHORT).show() if (!isTokenAvailable) { callLogin(userID, password) @@ -506,6 +512,10 @@ class HomeFragment : Fragment() { when (response) { is Result.Success -> { val updatedversion = response.data.data?.version.toString() + with(sharedPreference.edit()) { + putString("version", response.data.data?.version) + apply() + } val currentversion = context?.let { ctx -> val packageInfo = ctx.packageManager.getPackageInfo(ctx.packageName, 0) @@ -535,6 +545,7 @@ class HomeFragment : Fragment() { Toast.LENGTH_LONG ) .show() + } else { Toast.makeText( activity, diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/LoginFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/LoginFragment.kt index ea2a1fb..8eee324 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/LoginFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/LoginFragment.kt @@ -27,9 +27,12 @@ import android.view.ViewGroup import android.widget.Toast import androidx.annotation.RequiresApi import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.DataHolder +import com.example.hpostesting.data.model.login.LoginRequest +import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.databinding.FragmentLoginBinding import kotlinx.coroutines.Dispatchers @@ -49,6 +52,7 @@ class LoginFragment : Fragment() { private var _binding: FragmentLoginBinding? = null private val binding get() = _binding!! private lateinit var sharedPreference: SharedPreferences + private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, @@ -113,7 +117,9 @@ class LoginFragment : Fragment() { if (loginId.isNotBlank() && password.isNotBlank()) { performLogin(loginId, password) - + var Password = sharedPreference.getString(Constants.DEVICE_PASSWORD_API, "").toString() + var UserID = sharedPreference.getString(Constants.DEVICE_ID_API, "").toString() + hemoCubeViewModel.login(createLoginRequestData(UserID, Password)) } else { if (loginId.isBlank()) { binding.loginId.error = R.string.enter_proper_login_id.toString() @@ -124,7 +130,17 @@ class LoginFragment : Fragment() { } } } + private fun createLoginRequestData(userID: String, password: String): LoginRequest { + val pInfo = requireActivity().packageManager.getPackageInfo( + requireActivity().packageName, 0 + ) + val version = pInfo.versionName + var labname = sharedPreference.getString(Constants.LABNAME,"") + return LoginRequest( + password = password, serialNumber = userID, username = userID, version = version, lab = labname,location = DataHolder.ipAddress.toString() + ) + } private fun isUserLoggedIn(): Boolean { return sharedPreference.getString(Constants.USER_ID, "")?.isNotBlank() == true } diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt index b7e7fcc..ddaf8fc 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt @@ -54,6 +54,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import okhttp3.Headers import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MultipartBody import okhttp3.RequestBody.Companion.asRequestBody @@ -93,7 +94,8 @@ class HemoCubeViewModel @Inject constructor( val checkUpdate = MutableLiveData>() - val deviceUpdate = MutableLiveData>() + val deviceUpdate = MutableLiveData() + val deviceUpdateheader = MutableLiveData() val downloadcertificate = MutableLiveData>() val uploadLogs = MutableLiveData?>() @@ -259,9 +261,11 @@ class HemoCubeViewModel @Inject constructor( } fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch { - deviceUpdate.postValue(Result.Loading()) + //deviceUpdate.postValue(Result.Loading()) repository.deviceUpdate(deviceUpdateRequest).let { - deviceUpdate.postValue(it) + deviceUpdate.postValue(it.body()) + deviceUpdateheader.postValue(it.headers()) + } } diff --git a/app/src/main/java/com/example/hpostesting/presentation/trueheme/TrueHemeViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/trueheme/TrueHemeViewModel.kt index c287c6c..69cc110 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/trueheme/TrueHemeViewModel.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/trueheme/TrueHemeViewModel.kt @@ -162,7 +162,7 @@ class TrueHemeViewModel @Inject constructor( fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch { deviceUpdate.postValue(Result.Loading()) repository.deviceUpdate(deviceUpdateRequest).let { - deviceUpdate.postValue(it) +// deviceUpdate.postValue(it) } }