-
Notifications
You must be signed in to change notification settings - Fork 1
Develop/caching strategy #26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
ab0b504
7b79bb4
e0225a9
122cf5c
c308977
18674fb
c180dab
31aded3
0738d71
d99afaf
723b7ab
875afe3
ee4df16
99c3eb7
d0578bb
5704383
733bd4f
e1284d6
3c22ca4
0db8b43
7430eab
e1d66ad
688cd13
70b155f
9475a25
af37940
ea2ce09
dbfa995
f905c41
606cf35
6d2d7c4
fe10f55
18180af
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| kotlin version: 2.0.20 | ||
| error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output: | ||
| 1. Kotlin compile daemon is ready | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| kotlin version: 2.0.20 | ||
| error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output: | ||
| 1. Kotlin compile daemon is ready | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| ### Visit the android developers website | ||
| [Compila apps adaptables con las nuevas APIs de Compose, ahora estables](https://developer.android.com/?hl=es-419#:~:text=Discover%20the%20latest%20app%20development%20tools,) | ||
| # [Compila apps adaptables con las nuevas APIs de Compose, ahora estables](https://developer.android.com/?hl=es-419#:~:text=Discover%20the%20latest%20app%20development%20tools,) | ||
| no olvides configurar el gradle para una exitosa ejecución.. |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,7 +1,9 @@ | ||||||
| plugins { | ||||||
| id("com.android.application") version "8.6.1" // AGP version | ||||||
| id("org.jetbrains.kotlin.android") version "1.9.0" // Kotlin plugin for Android | ||||||
| id("org.jetbrains.kotlin.plugin.serialization") version "1.9.0" // Kotlin serialization plugin | ||||||
| id("org.jetbrains.kotlin.android") version "2.0.20" // Kotlin plugin for Android | ||||||
| id("org.jetbrains.kotlin.plugin.serialization") version "2.0.20" // Kotlin serialization plugin | ||||||
| id("org.jetbrains.kotlin.plugin.compose") version "2.0.20" | ||||||
| id ("kotlin-kapt") // Asegúrate de que kapt esté habilitado | ||||||
| } | ||||||
|
|
||||||
| android { | ||||||
|
|
@@ -69,14 +71,32 @@ dependencies { | |||||
| implementation("androidx.compose.ui:ui-graphics") | ||||||
| implementation("androidx.compose.ui:ui-tooling-preview") | ||||||
| implementation("androidx.compose.material3:material3:1.3.0") | ||||||
| implementation("androidx.navigation:navigation-runtime-ktx:2.8.2") | ||||||
| implementation("androidx.navigation:navigation-compose:2.8.2") | ||||||
| implementation ("androidx.biometric:biometric:1.1.0") | ||||||
| implementation("androidx.fragment:fragment-ktx:1.8.4") | ||||||
| implementation("com.google.android.gms:play-services-maps:19.0.0") | ||||||
| implementation("com.google.android.libraries.places:places:4.0.0") | ||||||
| implementation ("com.google.accompanist:accompanist-permissions:0.28.0") | ||||||
| implementation("androidx.appcompat:appcompat:1.7.0") | ||||||
| implementation ("com.google.maps.android:maps-compose:2.2.0") | ||||||
| implementation("androidx.room:room-common:2.6.1") | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Ensure consistent Room library versions The Room dependencies are using different versions:
Mixing different versions of Room components can lead to unexpected behavior or compatibility issues. It's recommended to align all Room dependencies to the same version. Apply this diff to synchronize the Room library versions: implementation("androidx.room:room-common:2.6.1")
-implementation("androidx.room:room-runtime:2.4.3")
+implementation("androidx.room:room-runtime:2.6.1")
-kapt ("androidx.room:room-compiler:2.5.1")
+kapt ("androidx.room:room-compiler:2.6.1") // Annotation processor for RoomAlso applies to: 85-85, 87-87 |
||||||
|
|
||||||
| implementation ("androidx.room:room-runtime:2.4.3") | ||||||
| implementation("androidx.compose.runtime:runtime-livedata:1.7.4") | ||||||
| kapt ("androidx.room:room-compiler:2.5.1") // Procesador de anotaciones para Room | ||||||
| implementation ("com.github.bumptech.glide:glide:4.12.") // Glide estándar | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct the incomplete Glide version number The Glide dependency on line 88 has an incomplete version number Apply this diff to specify the full version number: -implementation ("com.github.bumptech.glide:glide:4.12.") // Standard Glide
+implementation ("com.github.bumptech.glide:glide:4.12.0") // Standard Glide📝 Committable suggestion
Suggested change
|
||||||
| implementation ("com.github.bumptech.glide:compose:1.0.0-alpha.1") // Glide para Jetpack Compose | ||||||
| kapt ("com.github.bumptech.glide:compiler:4.12.0") // Para anotar métodos de Glide | ||||||
| // Testing dependencies | ||||||
| testImplementation("junit:junit:4.13.2") | ||||||
| androidTestImplementation("androidx.test.ext:junit:1.2.1") | ||||||
| androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1") | ||||||
| androidTestImplementation(platform("androidx.compose:compose-bom:2024.09.03")) | ||||||
| androidTestImplementation("androidx.compose.ui:ui-test-junit4") | ||||||
|
|
||||||
| testImplementation ("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0") | ||||||
| testImplementation ("junit:junit:4.13.2") | ||||||
|
Comment on lines
+97
to
+98
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Remove duplicate JUnit dependency The Apply this diff to remove the duplicate entry: testImplementation("junit:junit:4.13.2")
-testImplementation ("junit:junit:4.13.2")
|
||||||
| testImplementation ("io.mockk:mockk:1.13.3") // revisa la última versión | ||||||
| // Debug dependencies | ||||||
| debugImplementation("androidx.compose.ui:ui-tooling") | ||||||
| debugImplementation("androidx.compose.ui:ui-test-manifest") | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,6 +2,13 @@ | |||||||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||||||||
| xmlns:tools="http://schemas.android.com/tools"> | ||||||||||
| <uses-permission android:name="android.permission.INTERNET" /> | ||||||||||
| <uses-permission android:name="android.permission.USE_BIOMETRIC" /> | ||||||||||
|
|
||||||||||
| <uses-permission android:name="android.permission.USE_FINGERPRINT" /> | ||||||||||
|
Comment on lines
+5
to
+7
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Remove deprecated USE_FINGERPRINT permission The Apply this diff: <uses-permission android:name="android.permission.USE_BIOMETRIC" />
- <uses-permission android:name="android.permission.USE_FINGERPRINT" />📝 Committable suggestion
Suggested change
|
||||||||||
| <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> | ||||||||||
| <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> | ||||||||||
|
Comment on lines
+8
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Remove redundant COARSE_LOCATION permission The code only checks for and uses
🔗 Analysis chainVerify location permission requirements While requesting both
🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Description: Check how location is used in the codebase
# Search for location-related API calls to determine precision needs
echo "Searching for location API usage..."
rg -l "getLastLocation|requestLocationUpdates|FusedLocationProviderClient"
# Check for location permission checks
echo "Searching for permission checks..."
rg -l "checkSelfPermission.*FINE_LOCATION|checkSelfPermission.*COARSE_LOCATION"
Length of output: 476 Script: #!/bin/bash
# Check the specific location usage in RestaurantMapScreen.kt
echo "Checking location usage in RestaurantMapScreen.kt..."
rg -A 5 -B 5 "getLastLocation|requestLocationUpdates|FusedLocationProviderClient" "app/src/main/java/com/uniandes/ecobites/ui/screens/maps/RestaurantMapScreen.kt"
echo "\nChecking permission checks..."
rg -A 5 -B 5 "checkSelfPermission.*FINE_LOCATION|checkSelfPermission.*COARSE_LOCATION" "app/src/main/java/com/uniandes/ecobites/ui/screens/maps/RestaurantMapScreen.kt"
# Check if there's any location accuracy requirements mentioned
echo "\nChecking for location accuracy requirements..."
rg "accuracy|precise|approximate" "app/src/main/java/com/uniandes/ecobites/ui/screens/maps/RestaurantMapScreen.kt"
Length of output: 2982 |
||||||||||
|
|
||||||||||
|
|
||||||||||
| <application | ||||||||||
| android:allowBackup="true" | ||||||||||
| android:dataExtractionRules="@xml/data_extraction_rules" | ||||||||||
|
|
@@ -12,6 +19,10 @@ | |||||||||
| android:supportsRtl="true" | ||||||||||
| android:theme="@style/Theme.EcoBites" | ||||||||||
| tools:targetApi="31"> | ||||||||||
| <!-- Clave de la API de Google Maps --> | ||||||||||
| <meta-data | ||||||||||
| android:name="com.google.android.geo.API_KEY" | ||||||||||
| android:value="AIzaSyCTHkA6PG3Zr_nhxq8N7dlX-vrmEM4mltY"/> | ||||||||||
|
Comment on lines
+22
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Security: Protect Google Maps API key The Google Maps API key is exposed in plain text. While it's normal for this key to be in the manifest, it needs proper security measures:
Apply these changes:
MAPS_API_KEY=AIzaSyCTHkA6PG3Zr_nhxq8N7dlX-vrmEM4mltY
android {
defaultConfig {
manifestPlaceholders["MAPS_API_KEY"] = properties.getOrDefault("MAPS_API_KEY", "")
}
}
- <meta-data
- android:name="com.google.android.geo.API_KEY"
- android:value="AIzaSyCTHkA6PG3Zr_nhxq8N7dlX-vrmEM4mltY"/>
+ <meta-data
+ android:name="com.google.android.geo.API_KEY"
+ android:value="${MAPS_API_KEY}"/>
+ local.properties🧰 Tools🪛 Gitleaks25-25: Uncovered a GCP API key, which could lead to unauthorized access to Google Cloud services and data breaches. (gcp-api-key) |
||||||||||
| <activity | ||||||||||
| android:name=".MainActivity" | ||||||||||
| android:exported="true" | ||||||||||
|
|
||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -8,75 +8,40 @@ import androidx.compose.foundation.layout.padding | |||||||||||||||||||
| import androidx.compose.material3.Scaffold | ||||||||||||||||||||
| import androidx.compose.runtime.* | ||||||||||||||||||||
| import androidx.compose.ui.Modifier | ||||||||||||||||||||
| import com.uniandes.ecobites.ui.screens.ProfileScreen | ||||||||||||||||||||
| import com.uniandes.ecobites.ui.screens.CartScreen | ||||||||||||||||||||
| import com.uniandes.ecobites.ui.screens.home.HomeScreen | ||||||||||||||||||||
| import com.uniandes.ecobites.ui.theme.AppTheme | ||||||||||||||||||||
| import com.uniandes.ecobites.ui.components.NavBar | ||||||||||||||||||||
| import androidx.navigation.compose.rememberNavController | ||||||||||||||||||||
| import com.uniandes.ecobites.ui.SplashScreen | ||||||||||||||||||||
| import com.uniandes.ecobites.ui.screens.LoginScreen | ||||||||||||||||||||
| import io.github.jan.supabase.createSupabaseClient | ||||||||||||||||||||
| import com.uniandes.ecobites.ui.components.BiometricAuth | ||||||||||||||||||||
| import com.uniandes.ecobites.ui.navigation.NavigationHost | ||||||||||||||||||||
| import com.uniandes.ecobites.ui.theme.AppTheme | ||||||||||||||||||||
| import kotlinx.coroutines.delay | ||||||||||||||||||||
| import io.github.jan.supabase.auth.Auth | ||||||||||||||||||||
| import io.github.jan.supabase.postgrest.Postgrest | ||||||||||||||||||||
|
|
||||||||||||||||||||
| val supabase = createSupabaseClient( | ||||||||||||||||||||
| supabaseUrl = "https://nlhcaanwwchxdzdiyizf.supabase.co", | ||||||||||||||||||||
| supabaseKey = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im5saGNhYW53d2NoeGR6ZGl5aXpmIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Mjc5MDc0OTQsImV4cCI6MjA0MzQ4MzQ5NH0.LrcRGkVH1qjPE09xDngX7wrtrUmfIYbTGrgbPKarTeM" | ||||||||||||||||||||
| ) { | ||||||||||||||||||||
| install(Auth) | ||||||||||||||||||||
| install(Postgrest) | ||||||||||||||||||||
| //install other modules | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| class MainActivity : ComponentActivity() { | ||||||||||||||||||||
| override fun onCreate(savedInstanceState: Bundle?) { | ||||||||||||||||||||
| super.onCreate(savedInstanceState) | ||||||||||||||||||||
| val biometricAuth = BiometricAuth(this) | ||||||||||||||||||||
|
|
||||||||||||||||||||
| setContent { | ||||||||||||||||||||
| AppTheme { | ||||||||||||||||||||
| MyApp() | ||||||||||||||||||||
| MyApp(biometricAuth) | ||||||||||||||||||||
|
Comment on lines
+21
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid passing Activity context to Composables to prevent memory leaks Passing the Apply this diff to move the initialization of class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- val biometricAuth = BiometricAuth(this)
setContent {
AppTheme {
- MyApp(biometricAuth)
+ MyApp()
}
}
}
}
@Composable
-fun MyApp(biometricAuth: BiometricAuth) {
+fun MyApp() {
val navController = rememberNavController()
+ val context = LocalContext.current
+ val biometricAuth = remember { BiometricAuth(context) }
// Rest of the code...📝 Committable suggestion
Suggested change
|
||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| @Composable | ||||||||||||||||||||
| fun MyApp() { | ||||||||||||||||||||
| fun MyApp(biometricAuth: BiometricAuth) { | ||||||||||||||||||||
| val navController = rememberNavController() // Create the NavController | ||||||||||||||||||||
| var showSplashScreen by remember { mutableStateOf(true) } | ||||||||||||||||||||
| var isLoggedIn by remember { mutableStateOf(false) } // Track login state | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Show splash screen for 3 seconds before navigating to the main content | ||||||||||||||||||||
| // Show splash screen for 1.5 seconds before navigating to the main content | ||||||||||||||||||||
| LaunchedEffect(Unit) { | ||||||||||||||||||||
| delay(3000) // 3 seconds delay | ||||||||||||||||||||
| showSplashScreen = false // Hide splash screen after the delay | ||||||||||||||||||||
| delay(1500) | ||||||||||||||||||||
| showSplashScreen = false | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| if (showSplashScreen) { | ||||||||||||||||||||
| SplashScreen() // Show splash screen | ||||||||||||||||||||
| } else if (!isLoggedIn) { | ||||||||||||||||||||
| LoginScreen(onLoginSuccess = { isLoggedIn = true }) // Pass a callback to update isLoggedIn | ||||||||||||||||||||
| SplashScreen() | ||||||||||||||||||||
| } else { | ||||||||||||||||||||
| MainContent() // Show main content if logged in | ||||||||||||||||||||
| NavigationHost(navController = navController, biometricAuth = biometricAuth) // Pass the NavController here | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
|
|
||||||||||||||||||||
| @Composable | ||||||||||||||||||||
| fun MainContent() { | ||||||||||||||||||||
| var selectedTab by remember { mutableIntStateOf(0) } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Scaffold( | ||||||||||||||||||||
| bottomBar = { | ||||||||||||||||||||
| NavBar(selectedTab = selectedTab, onTabSelected = { tab -> selectedTab = tab }) | ||||||||||||||||||||
| } | ||||||||||||||||||||
| ) { innerPadding -> | ||||||||||||||||||||
| Box(modifier = Modifier.padding(innerPadding)) { | ||||||||||||||||||||
| when (selectedTab) { | ||||||||||||||||||||
| 0 -> HomeScreen() | ||||||||||||||||||||
| 1 -> CartScreen() | ||||||||||||||||||||
| 3 -> ProfileScreen() | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| package com.uniandes.ecobites.ui.components | ||
|
|
||
| import android.Manifest | ||
| import android.app.Activity | ||
| import android.content.Context | ||
| import android.content.pm.PackageManager | ||
| import android.hardware.fingerprint.FingerprintManager | ||
| import android.os.CancellationSignal | ||
| import androidx.core.app.ActivityCompat | ||
| import androidx.navigation.NavController | ||
|
|
||
| class BiometricAuth(private val context: Context) { | ||
|
Comment on lines
+1
to
+12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Migrate to BiometricPrompt API for better security and user experience. The implementation uses the deprecated
Here's how to refactor using BiometricPrompt: import androidx.biometric.BiometricPrompt
import androidx.biometric.BiometricManager
import androidx.fragment.app.FragmentActivity
class BiometricAuth(private val context: Context) {
private val biometricManager = BiometricManager.from(context)
private val executor = ContextCompat.getMainExecutor(context) |
||
|
|
||
| private var cancellationSignal: CancellationSignal? = null | ||
|
|
||
| // agregamos el navController para la navegación | ||
| private var navController: NavController? = null | ||
|
|
||
|
|
||
| private val authenticationCallback: FingerprintManager.AuthenticationCallback = | ||
| object : FingerprintManager.AuthenticationCallback() { | ||
| @Deprecated("Deprecated in Java") | ||
| override fun onAuthenticationSucceeded(result: FingerprintManager.AuthenticationResult) { | ||
| super.onAuthenticationSucceeded(result) | ||
| // Aquí manejo el éxito de la autenticación | ||
| navController?.navigate("home") { | ||
| popUpTo("login") { inclusive = true} | ||
| } | ||
| } | ||
|
|
||
| @Deprecated("Deprecated in Java") | ||
| override fun onAuthenticationFailed() { | ||
| super.onAuthenticationFailed() | ||
| // Aquí manejo la autenticación fallida | ||
| } | ||
| } | ||
|
Comment on lines
+14
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve code robustness and maintainability. Several improvements needed:
Apply these improvements: - private var navController: NavController? = null
+ private lateinit var navController: NavController
- // agregamos el navController para la navegación
- private val authenticationCallback: FingerprintManager.AuthenticationCallback =
+ private val authenticationCallback = BiometricPrompt.AuthenticationCallback() {
+ override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
+ super.onAuthenticationSucceeded(result)
+ navController.navigate("home") {
+ popUpTo("login") { inclusive = true }
+ }
+ }
+
+ override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
+ super.onAuthenticationError(errorCode, errString)
+ // Handle specific error codes
+ }
+
+ override fun onAuthenticationFailed() {
+ super.onAuthenticationFailed()
+ // Show error message to user
+ }
}
|
||
|
|
||
| // Función para verificar si la autenticación por huella está soportada en el dispositivo | ||
| fun isFingerprintSupported(): Boolean { | ||
| val fingerprintManager = context.getSystemService(Context.FINGERPRINT_SERVICE) as FingerprintManager | ||
|
|
||
| return if (ActivityCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) { | ||
| false | ||
| } else { | ||
| fingerprintManager.isHardwareDetected && fingerprintManager.hasEnrolledFingerprints() | ||
| } | ||
| } | ||
|
Comment on lines
+38
to
+47
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update biometric support check for better security and error handling. Current implementation has several issues:
Implement proper error handling and use modern APIs: fun isBiometricSupported(): Boolean {
return when (biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG)) {
BiometricManager.BIOMETRIC_SUCCESS -> true
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE,
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE,
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> false
else -> false
}
} |
||
|
|
||
| // Función para iniciar la autenticación por huella y navegar a la pantalla de home si la navegación es exitosa | ||
| fun authenticate(navController: NavController) { | ||
| this.navController = navController // guardamos el navController para poder navegar después | ||
| val fingerprintManager = context.getSystemService(Context.FINGERPRINT_SERVICE) as FingerprintManager | ||
|
|
||
| if (ActivityCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) { | ||
| ActivityCompat.requestPermissions( | ||
| context as Activity, | ||
| arrayOf(Manifest.permission.USE_FINGERPRINT,Manifest.permission.USE_BIOMETRIC), | ||
| 101 | ||
| )// Permisos de huella no están concedidos, manejo de caso | ||
| return | ||
| } | ||
|
|
||
| cancellationSignal = CancellationSignal() | ||
|
|
||
| fingerprintManager.authenticate(null, cancellationSignal, 0, authenticationCallback, null) | ||
| } | ||
|
Comment on lines
+49
to
+66
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Address security vulnerabilities in authentication implementation. Several critical security issues need attention:
Implement secure authentication: fun authenticate(activity: FragmentActivity, onError: (String) -> Unit) {
val promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Biometric Authentication")
.setSubtitle("Log in using your biometric credential")
.setNegativeButtonText("Cancel")
.build()
BiometricPrompt(activity, executor, authenticationCallback)
.authenticate(promptInfo)
}Consider implementing these security improvements:
|
||
| } | ||
|
Comment on lines
+1
to
+67
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Security concerns identified in biometric authentication implementation The current implementation has several security issues:
Recommendations:
🔗 Analysis chainVerify the security context of biometric authentication usage. Since this is a security-critical component, we should verify how it's being used in the authentication flow. Let me gather more information about the authentication flow and security checks. Let me check one more aspect about the login screen implementation to understand how biometric auth is integrated with other authentication methods. 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Check how BiometricAuth is used in the codebase
echo "Checking BiometricAuth usage patterns..."
# Look for direct instantiations
rg "BiometricAuth\(" -A 5
# Check navigation patterns to understand the authentication flow
rg "navigate\(\"login\"|navigate\(\"home\"" -A 5
# Look for other security checks around these routes
ast-grep --pattern 'fun $_(navController: NavController) {
$$$
navigate("home")
$$$
}'
Length of output: 4563 Script: #!/bin/bash
# Check the NavigationHost implementation to understand the auth flow
rg -g "NavigationHost.kt" "composable\(\"login\"|composable\(\"home\"" -B 2 -A 10
# Look for any authentication state management
rg "authenticate|login|signIn" -t kt -A 5
# Check for any security-related configurations
rg -g "*.kt" "SecurityConfig|Authentication|@Secure" -A 5
Length of output: 4976 Script: #!/bin/bash
# Check LoginScreen implementation
rg -g "LoginScreen.kt" "BiometricAuth|authenticate" -B 5 -A 10
# Look for any credential validation or auth state management
rg -g "LoginScreen.kt" "onLoginSuccess|password|credentials" -B 2 -A 5
Length of output: 7399 |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,34 +6,46 @@ import androidx.compose.material.icons.rounded.Home | |
| import androidx.compose.material.icons.rounded.ShoppingCart | ||
| import androidx.compose.material.icons.rounded.List | ||
| import androidx.compose.material.icons.rounded.Person | ||
| import androidx.compose.material.icons.rounded.LocationOn // Nuevo ícono de ubicación | ||
| import androidx.compose.runtime.Composable | ||
| import androidx.navigation.NavController | ||
| import androidx.navigation.compose.currentBackStackEntryAsState | ||
|
|
||
| @Composable | ||
| fun NavBar(selectedTab: Int, onTabSelected: (Int) -> Unit) { | ||
| fun NavBar(navController: NavController) { | ||
| val currentRoute = navController.currentBackStackEntryAsState()?.value?.destination?.route | ||
|
|
||
| NavigationBar { | ||
| NavigationBarItem( | ||
| icon = { Icon(Icons.Rounded.Home, contentDescription = "Home") }, | ||
| label = { Text("Home") }, | ||
| selected = selectedTab == 0, | ||
| onClick = { onTabSelected(0) } | ||
| selected = currentRoute == "home", | ||
| onClick = { navController.navigate("home") } | ||
|
Comment on lines
+22
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Extract route names into constants to prevent typos. Using hardcoded strings for routes across multiple places is error-prone. Consider creating a sealed class or object to manage route constants. object NavRoutes {
const val HOME = "home"
const val CART = "cart"
const val ORDERS = "orders"
const val PROFILE = "profile"
const val LOCATION = "location"
}Then use it like: - selected = currentRoute == "home",
- onClick = { navController.navigate("home") }
+ selected = currentRoute == NavRoutes.HOME,
+ onClick = { navController.navigate(NavRoutes.HOME) }Also applies to: 28-29, 34-35, 40-41 |
||
| ) | ||
| NavigationBarItem( | ||
| icon = { Icon(Icons.Rounded.ShoppingCart, contentDescription = "Cart") }, | ||
| label = { Text("Cart") }, | ||
| selected = selectedTab == 1, | ||
| onClick = { onTabSelected(1) } | ||
| selected = currentRoute == "cart", | ||
| onClick = { navController.navigate("cart") } | ||
| ) | ||
| NavigationBarItem( | ||
| icon = { Icon(Icons.Rounded.List, contentDescription = "Orders") }, | ||
| label = { Text("Orders") }, | ||
| selected = selectedTab == 2, | ||
| onClick = { onTabSelected(2) } | ||
| selected = currentRoute == "orders", | ||
| onClick = { navController.navigate("orders") } | ||
| ) | ||
| NavigationBarItem( | ||
| icon = { Icon(Icons.Rounded.Person, contentDescription = "Profile") }, | ||
| label = { Text("Profile") }, | ||
| selected = selectedTab == 3, | ||
| onClick = { onTabSelected(3) } | ||
| selected = currentRoute == "profile", | ||
| onClick = { navController.navigate("profile") } | ||
| ) | ||
| // Nuevo ítem de Location | ||
| NavigationBarItem( | ||
| icon = { Icon(Icons.Rounded.LocationOn, contentDescription = "Location") }, // Ícono de ubicación | ||
| label = { Text("Location") }, | ||
| selected = currentRoute == "location", | ||
| onClick = { navController.navigate("location") } | ||
| ) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,19 @@ | ||||||||||||||||
| package com.uniandes.ecobites.ui.data | ||||||||||||||||
|
|
||||||||||||||||
| import androidx.lifecycle.LiveData | ||||||||||||||||
| import androidx.room.Dao | ||||||||||||||||
| import androidx.room.Delete | ||||||||||||||||
| import androidx.room.Insert | ||||||||||||||||
| import androidx.room.Query | ||||||||||||||||
|
|
||||||||||||||||
| @Dao | ||||||||||||||||
| interface MenuDao { | ||||||||||||||||
| @Query("SELECT * FROM MenuItem") | ||||||||||||||||
| fun getAllMenuItems(): LiveData<List<MenuItem>> | ||||||||||||||||
|
|
||||||||||||||||
| @Insert | ||||||||||||||||
| fun saveMenuItem(menuItem: MenuItem) | ||||||||||||||||
|
Comment on lines
+14
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add conflict resolution and coroutine support. The current implementation lacks:
-@Insert
-fun saveMenuItem(menuItem: MenuItem)
+@Insert(onConflict = OnConflictStrategy.REPLACE)
+suspend fun saveMenuItem(menuItem: MenuItem)Don't forget to add the import: import androidx.room.OnConflictStrategy |
||||||||||||||||
|
|
||||||||||||||||
| @Delete | ||||||||||||||||
| fun deleteMenuItem(menuItem: MenuItem) | ||||||||||||||||
|
Comment on lines
+17
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add coroutine support and bulk delete operation. Enhance the delete functionality with:
-@Delete
-fun deleteMenuItem(menuItem: MenuItem)
+@Delete
+suspend fun deleteMenuItem(menuItem: MenuItem)
+
+@Delete
+suspend fun deleteMenuItems(menuItems: List<MenuItem>)📝 Committable suggestion
Suggested change
|
||||||||||||||||
| } | ||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package com.uniandes.ecobites.ui.data | ||
|
|
||
| import androidx.room.Database | ||
| import androidx.room.RoomDatabase | ||
|
|
||
| @Database(entities = [MenuItem::class], version = 1) | ||
| abstract class MenuDatabase : RoomDatabase() { | ||
| abstract fun menuDao(): MenuDao | ||
| } | ||
|
Comment on lines
+6
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification 🛠️ Refactor suggestion Database implementation needs improvement - issues found in current setup The verification revealed several issues with the current database implementation:
// In NavigationHost.kt
val menuDatabase = Room.databaseBuilder(
LocalContext.current,
MenuDatabase::class.java,
"menu.db"
).build()
The original review comment's suggestions are valid and necessary for a production-ready implementation. Please implement the suggested changes, particularly:
🔗 Analysis chainEssential improvements needed for production-ready database implementation. While the basic setup is correct, several critical components are missing for a robust Room database implementation:
Apply these improvements: +@Database(
+ entities = [MenuItem::class],
+ version = 1,
+ exportSchema = true
+)
-@Database(entities = [MenuItem::class], version = 1)
abstract class MenuDatabase : RoomDatabase() {
abstract fun menuDao(): MenuDao
+
+ companion object {
+ @Volatile
+ private var INSTANCE: MenuDatabase? = null
+ private const val DATABASE_NAME = "menu_database"
+
+ fun getDatabase(context: Context): MenuDatabase {
+ return INSTANCE ?: synchronized(this) {
+ val instance = Room.databaseBuilder(
+ context.applicationContext,
+ MenuDatabase::class.java,
+ DATABASE_NAME
+ )
+ .addMigrations() // Add migrations here when updating version
+ .build()
+ INSTANCE = instance
+ instance
+ }
+ }
+ }
}Don't forget to:
android {
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments += [
"room.schemaLocation": "$projectDir/schemas".toString()
]
}
}
}
}Let's verify if any migrations exist in the codebase: 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Description: Check for existing migration files and schema tracking
# Test 1: Look for migration files
echo "Checking for migration files..."
fd -e kt -e java --full-path ".*[Mm]igration.*"
# Test 2: Check build.gradle for schema location configuration
echo "Checking build.gradle for schema configuration..."
rg "room.schemaLocation" -A 3 -B 3
Length of output: 266 Script: #!/bin/bash
# Let's verify the current database implementation and usage
# Check for database instance creation and configuration
echo "Checking database instance creation patterns..."
rg -A 10 "RoomDatabase\(\)"
# Look for database builder configurations
echo "Checking database builder patterns..."
rg -A 10 "Room\.databaseBuilder"
# Check if there's any schema directory or configuration
echo "Checking for schema related configurations..."
fd "schemas"
# Check build.gradle files for Room configuration
echo "Checking build.gradle files for Room setup..."
fd "build.gradle" --exec cat {}
Length of output: 6325 |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package com.uniandes.ecobites.ui.data | ||
|
|
||
| import androidx.room.Entity | ||
| import androidx.room.PrimaryKey | ||
|
|
||
| @Entity | ||
| data class MenuItem( | ||
| @PrimaryKey val id: String, | ||
| val name: String, | ||
| val price: Double | ||
| ) | ||
|
Comment on lines
+6
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance the Room entity with additional annotations and constraints. The current implementation could benefit from several Room best practices and data validation improvements: Apply these enhancements: -@Entity
+@Entity(
+ tableName = "menu_items",
+ indices = [Index(value = ["name"])]
+)
data class MenuItem(
- @PrimaryKey val id: String,
- val name: String,
- val price: Double
+ @PrimaryKey
+ @ColumnInfo(name = "id")
+ val id: String,
+
+ @ColumnInfo(name = "name")
+ @NonNull
+ val name: String,
+
+ @ColumnInfo(name = "price")
+ @NonNull
+ val price: Double
) {
+ init {
+ require(price >= 0) { "Price must be non-negative" }
+ require(name.isNotBlank()) { "Name must not be blank" }
+ }
}Don't forget to add these imports: import androidx.room.ColumnInfo
import androidx.room.Index
import androidx.annotation.NonNull |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Align Navigation and Accompanist library versions with Compose
The versions of Navigation and Accompanist libraries should be compatible with your Compose version to prevent runtime issues.
Verify that these libraries are compatible with your Compose BOM version:
androidx.navigation:navigation-*com.google.accompanist:accompanist-permissionscom.google.maps.android:maps-composeAlso applies to: 80-80, 82-82