diff --git a/build.gradle.kts b/build.gradle.kts index 42e2d2c..7386d7f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,4 +8,5 @@ plugins { alias(libs.plugins.kotlin.serialization) apply false alias(libs.plugins.hilt) apply false alias(libs.plugins.ksp) apply false + alias(libs.plugins.protobuf) apply false } \ No newline at end of file diff --git a/core/data/build.gradle.kts b/core/data/build.gradle.kts index ee4ccdf..023da1e 100644 --- a/core/data/build.gradle.kts +++ b/core/data/build.gradle.kts @@ -3,16 +3,40 @@ import com.yapp.app.setNamespace plugins { id("yapp.android.library") id("yapp.android.hilt") + alias(libs.plugins.protobuf) } -android{ +android { setNamespace("core.data") } +protobuf { + protoc { + artifact = libs.protobuf.protoc.get().toString() + } + generateProtoTasks { + all().forEach { task -> + task.builtins { + register("java") { + option("lite") + } + } + } + } +} + dependencies { implementation(project(":core:model")) implementation(project(":core:data-api")) + implementation(libs.androidx.datastore.core) + implementation(libs.androidx.datastore.preferences) + implementation(libs.protobuf.kotlin.lite) + + ksp(libs.encrypted.datastore.preference.ksp) + implementation(libs.encrypted.datastore.preference.ksp.annotations) + implementation(libs.encrypted.datastore.preference.security) + implementation(libs.androidx.core.ktx) implementation(libs.retrofit.core) implementation(libs.retrofit.kotlin.serialization) diff --git a/core/data/src/main/java/com/yapp/core/data/local/DataStoreModule.kt b/core/data/src/main/java/com/yapp/core/data/local/DataStoreModule.kt new file mode 100644 index 0000000..99b9dc7 --- /dev/null +++ b/core/data/src/main/java/com/yapp/core/data/local/DataStoreModule.kt @@ -0,0 +1,58 @@ +package com.yapp.core.data.local + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler +import androidx.datastore.preferences.core.PreferenceDataStoreFactory +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.emptyPreferences +import androidx.datastore.preferences.preferencesDataStoreFile +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import tech.thdev.useful.encrypted.data.store.preferences.security.generateUsefulSecurity +import javax.inject.Qualifier +import javax.inject.Singleton + +@InstallIn(SingletonComponent::class) +@Module +internal object DataStoreModule { + + @Singleton + @Provides + fun provideDataStore(@ApplicationContext context: Context): DataStore { + return PreferenceDataStoreFactory.create( + corruptionHandler = ReplaceFileCorruptionHandler( + produceNewData = { emptyPreferences() }, + ), + produceFile = { context.preferencesDataStoreFile(DATASTORE_NAME) }, + ) + } + + @EncryptedDataStore + @Singleton + @Provides + fun providedEncryptedDataStore(@ApplicationContext context: Context): DataStore { + return PreferenceDataStoreFactory.create( + corruptionHandler = ReplaceFileCorruptionHandler( + produceNewData = { emptyPreferences() }, + ), + produceFile = { context.preferencesDataStoreFile(ENCRYPTED_DATASTORE_NAME) }, + ) + } + + @Singleton + @Provides + fun provideSecurityPreference( + @EncryptedDataStore dataStore: DataStore, + ): SecurityPreferences = dataStore.generateSecurityPreferences(generateUsefulSecurity()) + + private const val DATASTORE_NAME = "yapp-datastore" + private const val ENCRYPTED_DATASTORE_NAME = "yapp-datastore-encrypted" +} + +@Qualifier +@Retention(AnnotationRetention.BINARY) +internal annotation class EncryptedDataStore diff --git a/core/data/src/main/java/com/yapp/core/data/local/SecurityPreferences.kt b/core/data/src/main/java/com/yapp/core/data/local/SecurityPreferences.kt new file mode 100644 index 0000000..59de5ec --- /dev/null +++ b/core/data/src/main/java/com/yapp/core/data/local/SecurityPreferences.kt @@ -0,0 +1,31 @@ +package com.yapp.core.data.local + +import kotlinx.coroutines.flow.Flow +import tech.thdev.useful.encrypted.data.store.preferences.ksp.annotations.UsefulPreferences +import tech.thdev.useful.encrypted.data.store.preferences.ksp.annotations.value.ClearValues +import tech.thdev.useful.encrypted.data.store.preferences.ksp.annotations.value.GetValue +import tech.thdev.useful.encrypted.data.store.preferences.ksp.annotations.value.SetValue + +@UsefulPreferences +interface SecurityPreferences { + + @GetValue(KEY_ACCESS_TOKEN, defaultValue = "") + fun flowAccessToken(): Flow + + @SetValue(KEY_ACCESS_TOKEN) + suspend fun setAccessToken(value: String) + + @GetValue(KEY_REFRESH_TOKEN, defaultValue = "") + fun flowRefreshToken(): Flow + + @SetValue(KEY_REFRESH_TOKEN) + suspend fun setRefreshToken(value: String) + + @ClearValues + suspend fun clearAll() + + companion object { + private const val KEY_ACCESS_TOKEN = "key-access-token" + private const val KEY_REFRESH_TOKEN = "key-refresh-token" + } +} diff --git a/core/model/src/main/java/com/yapp/model/YappJWT.kt b/core/model/src/main/java/com/yapp/model/YappJWT.kt deleted file mode 100644 index 3a0b8c7..0000000 --- a/core/model/src/main/java/com/yapp/model/YappJWT.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.yapp.model - -data class YappJWT( - val accessToken: String, - val refreshToken: String, -) \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3642a05..500ca19 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,6 +28,11 @@ okhttp = "4.12.0" timber = "5.0.1" +androidxDatastore = "1.1.2" +encryptedDatastore = "1.9.25-1.0.20-1.2.0" +protobuf = "3.24.4" +protobufPlugin = "0.9.4" + [libraries] android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "agp" } @@ -68,6 +73,15 @@ okhttp-logging = { group = "com.squareup.okhttp3", name = "logging-interceptor", timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "timber" } +androidx-datastore-core = { group = "androidx.datastore", name = "datastore", version.ref = "androidxDatastore" } +androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "androidxDatastore" } +encrypted-datastore-preference-ksp = { group = "tech.thdev", name = "useful-encrypted-data-store-preferences-ksp", version.ref = "encryptedDatastore" } +encrypted-datastore-preference-ksp-annotations = { group = "tech.thdev", name = "useful-encrypted-data-store-preferences-ksp-annotations", version.ref = "encryptedDatastore" } +encrypted-datastore-preference-security = { group = "tech.thdev", name = "useful-encrypted-data-store-preferences-security", version.ref = "encryptedDatastore" } + +protobuf-kotlin-lite = { group = "com.google.protobuf", name = "protobuf-kotlin-lite", version.ref = "protobuf" } +protobuf-protoc = { group = "com.google.protobuf", name = "protoc", version.ref = "protobuf" } + [plugins] android-application = { id = "com.android.application", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" } @@ -77,3 +91,4 @@ kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", versi jetbrains-kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "jetbrainsKotlinJvm" } hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } +protobuf = { id = "com.google.protobuf", version.ref = "protobufPlugin" }