Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions app/src/main/java/com/threegap/bitnagil/di/core/DataStoreModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.threegap.bitnagil.di.core

import android.content.Context
import com.threegap.bitnagil.datastore.auth.crypto.TokenCrypto
import com.threegap.bitnagil.datastore.auth.serializer.AuthTokenSerializer
import com.threegap.bitnagil.datastore.auth.storage.AuthTokenDataStore
import com.threegap.bitnagil.datastore.auth.storage.AuthTokenStorageFactory
import com.threegap.bitnagil.security.crypto.Crypto
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object DataStoreModule {

@Singleton
@Provides
fun provideTokenCrypto(crypto: Crypto): TokenCrypto =
object : TokenCrypto {
override fun encrypt(bytes: ByteArray): ByteArray = crypto.encrypt(bytes)

override fun decrypt(bytes: ByteArray): ByteArray = crypto.decrypt(bytes)
}

@Provides
@Singleton
fun provideAuthTokenStorage(
@ApplicationContext context: Context,
serializer: AuthTokenSerializer,
): AuthTokenDataStore = AuthTokenStorageFactory.create(context, serializer)
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.threegap.bitnagil.di
package com.threegap.bitnagil.di.core

import com.threegap.bitnagil.BuildConfig
import com.threegap.bitnagil.datastore.auth.storage.AuthTokenDataStore
import com.threegap.bitnagil.network.auth.AuthInterceptor
import com.threegap.bitnagil.network.token.TokenProvider
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.flow.first
import kotlinx.serialization.json.Json
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaType
Expand Down Expand Up @@ -107,4 +110,11 @@ object NetworkModule {
.addConverterFactory(converterFactory)
.client(okHttpClient)
.build()

@Provides
@Singleton
fun provideTokenStore(dataStore: AuthTokenDataStore): TokenProvider =
object : TokenProvider {
override suspend fun getToken(): String? = dataStore.tokenFlow.first().accessToken
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.threegap.bitnagil.di
package com.threegap.bitnagil.di.core

import javax.inject.Qualifier

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.threegap.bitnagil.security.di
package com.threegap.bitnagil.di.core

import com.threegap.bitnagil.security.crypto.Crypto
import com.threegap.bitnagil.security.crypto.SecureCrypto
Expand All @@ -13,6 +13,7 @@ import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object SecurityModule {

@Provides
@Singleton
fun provideKeyProvider(): KeyProvider = AndroidKeyProvider()
Expand Down
3 changes: 0 additions & 3 deletions core/datastore/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
plugins {
alias(libs.plugins.bitnagil.android.library)
alias(libs.plugins.bitnagil.android.hilt)
alias(libs.plugins.kotlin.serialization)
}

Expand All @@ -9,8 +8,6 @@ android {
}

dependencies {
implementation(projects.core.security)

implementation(libs.androidx.datastore.preferences)
implementation(libs.kotlinx.serialization.json)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.threegap.bitnagil.datastore.auth.crypto

interface TokenCrypto {
fun encrypt(bytes: ByteArray): ByteArray
fun decrypt(bytes: ByteArray): ByteArray
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.threegap.bitnagil.datastore.model
package com.threegap.bitnagil.datastore.auth.model

import kotlinx.serialization.Serializable

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.threegap.bitnagil.datastore.auth.serializer

import androidx.datastore.core.Serializer
import com.threegap.bitnagil.datastore.auth.model.AuthToken

interface AuthTokenSerializer : Serializer<AuthToken>
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
package com.threegap.bitnagil.datastore.serializer
package com.threegap.bitnagil.datastore.auth.serializer

import com.threegap.bitnagil.datastore.model.AuthToken
import com.threegap.bitnagil.security.crypto.Crypto
import androidx.datastore.core.Serializer
import com.threegap.bitnagil.datastore.auth.crypto.TokenCrypto
import com.threegap.bitnagil.datastore.auth.model.AuthToken
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import java.io.InputStream
import java.io.OutputStream
import java.util.Base64
import javax.inject.Inject

internal class AuthTokenSerializer @Inject constructor(
private val crypto: Crypto,
) : TokenSerializer {
class AuthTokenSerializerImpl(
private val crypto: TokenCrypto,
) : Serializer<AuthToken> {
override val defaultValue: AuthToken
get() = AuthToken()

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.threegap.bitnagil.datastore.storage
package com.threegap.bitnagil.datastore.auth.storage

import com.threegap.bitnagil.datastore.model.AuthToken
import com.threegap.bitnagil.datastore.auth.model.AuthToken
import kotlinx.coroutines.flow.Flow

interface AuthTokenDataStore {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package com.threegap.bitnagil.datastore.storage
package com.threegap.bitnagil.datastore.auth.storage

import android.util.Log
import androidx.datastore.core.DataStore
import com.threegap.bitnagil.datastore.model.AuthToken
import com.threegap.bitnagil.datastore.auth.model.AuthToken
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject

internal class AuthTokenDataStoreImpl @Inject constructor(
class AuthTokenDataStoreImpl(
private val dataStore: DataStore<AuthToken>,
) : AuthTokenDataStore {
override val tokenFlow: Flow<AuthToken> = dataStore.data
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.threegap.bitnagil.datastore.auth.storage

import android.content.Context
import androidx.datastore.core.DataStoreFactory
import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler
import androidx.datastore.dataStoreFile
import com.threegap.bitnagil.datastore.auth.model.AuthToken
import com.threegap.bitnagil.datastore.auth.serializer.AuthTokenSerializer

object AuthTokenStorageFactory {
fun create(context: Context, serializer: AuthTokenSerializer): AuthTokenDataStore {
val dataStore = DataStoreFactory.create(
serializer = serializer,
produceFile = { context.dataStoreFile("auth-token.enc") },
corruptionHandler = ReplaceFileCorruptionHandler { AuthToken() },
)

return AuthTokenDataStoreImpl(dataStore)
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.threegap.bitnagil.datastore.serializer
package com.threegap.bitnagil.datastore.auth.serializer

import com.threegap.bitnagil.datastore.model.AuthToken
import com.threegap.bitnagil.security.crypto.Crypto
import com.threegap.bitnagil.datastore.auth.crypto.TokenCrypto
import com.threegap.bitnagil.datastore.auth.model.AuthToken
import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.Json
import org.junit.Assert.assertEquals
Expand All @@ -11,8 +11,8 @@ import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.util.Base64

class AuthTokenSerializerTest {
private lateinit var serializer: AuthTokenSerializer
class AuthAuthTokenSerializerImplTest {
Comment thread
wjdrjs00 marked this conversation as resolved.
Outdated
private lateinit var serializer: AuthTokenSerializerImpl
private lateinit var crypto: FakeCrypto
private lateinit var fakeToken: AuthToken
private lateinit var encrypted: ByteArray
Expand All @@ -22,7 +22,7 @@ class AuthTokenSerializerTest {
private val encryptResult: ByteArray,
private val decryptResult: ByteArray,
private val shouldFailDecrypt: Boolean = false,
) : Crypto {
) : TokenCrypto {
override fun encrypt(bytes: ByteArray): ByteArray = encryptResult

override fun decrypt(bytes: ByteArray): ByteArray {
Expand All @@ -43,7 +43,7 @@ class AuthTokenSerializerTest {
decryptResult = json.toByteArray(),
)

serializer = AuthTokenSerializer(crypto)
serializer = AuthTokenSerializerImpl(crypto)
}

@Test
Expand Down Expand Up @@ -84,7 +84,7 @@ class AuthTokenSerializerTest {
decryptResult = byteArrayOf(),
shouldFailDecrypt = true,
)
val brokenSerializer = AuthTokenSerializer(brokenCrypto)
val brokenSerializer = AuthTokenSerializerImpl(brokenCrypto)
val inputStream = ByteArrayInputStream(Base64.getEncoder().encode(encrypted))

// when
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.threegap.bitnagil.datastore.storage
package com.threegap.bitnagil.datastore.auth.storage

import androidx.datastore.core.DataStore
import androidx.datastore.core.DataStoreFactory
import androidx.datastore.core.Serializer
import com.threegap.bitnagil.datastore.model.AuthToken
import com.threegap.bitnagil.datastore.auth.model.AuthToken
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOf
Expand Down
2 changes: 0 additions & 2 deletions core/network/build.gradle.kts
Comment thread
wjdrjs00 marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ android {
}

dependencies {
implementation(projects.core.datastore)

implementation(libs.kotlinx.serialization.json)
implementation(platform(libs.retrofit.bom))
implementation(libs.bundles.retrofit)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
package com.threegap.bitnagil.network.auth

import com.threegap.bitnagil.datastore.storage.AuthTokenDataStore
import kotlinx.coroutines.flow.first
import com.threegap.bitnagil.network.token.TokenProvider
import kotlinx.coroutines.runBlocking
import okhttp3.Interceptor
import okhttp3.Response
import javax.inject.Inject

class AuthInterceptor @Inject constructor(
private val dataStore: AuthTokenDataStore,
private val tokenProvider: TokenProvider,
) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val token = runBlocking { dataStore.tokenFlow.first().accessToken }
val token = runBlocking { tokenProvider.getToken() }
if (token.isNullOrBlank()) {
return chain.proceed(originalRequest)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,20 @@
package com.threegap.bitnagil.network.auth

import com.threegap.bitnagil.datastore.storage.AuthTokenDataStore
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import okhttp3.Authenticator
import okhttp3.Request
import okhttp3.Response
import okhttp3.Route
import javax.inject.Inject

class TokenAuthenticator @Inject constructor(
private val dataStore: AuthTokenDataStore,
) : Authenticator {
class TokenAuthenticator @Inject constructor() : Authenticator {

override fun authenticate(route: Route?, response: Response): Request? {
if (response.code != UNAUTHORIZED) return null
if (responseCount(response) >= MAX_RETRY) return null

// 재발급 api 연결 시 수정 예정입니다.(현재 코드는 임시)
val newAccessToken = runBlocking {
runCatching { dataStore.tokenFlow.first().refreshToken }.getOrNull()
} ?: return null
val newAccessToken = runBlocking {}

return response.request.newBuilder()
.header(AUTHORIZATION, "$BEARER $newAccessToken")
Comment thread
wjdrjs00 marked this conversation as resolved.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.threegap.bitnagil.network.token

interface TokenProvider {
suspend fun getToken(): String?
}
1 change: 0 additions & 1 deletion core/security/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
plugins {
alias(libs.plugins.bitnagil.android.library)
alias(libs.plugins.bitnagil.android.hilt)
}

android {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.threegap.bitnagil.security.keystore.KeyProvider
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec

internal class SecureCrypto(
class SecureCrypto(
private val keyProvider: KeyProvider,
private val transformation: String = "AES/CBC/PKCS7Padding",
) : Crypto {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import java.security.KeyStore
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey

internal class AndroidKeyProvider : KeyProvider {
class AndroidKeyProvider : KeyProvider {
private val keyStore =
KeyStore
.getInstance("AndroidKeyStore")
Expand Down