-
Notifications
You must be signed in to change notification settings - Fork 0
[feat/#8] kakao login #17
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
Merged
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
37395bf
feat/#8 : kakao SDK setting
dmp100 8903729
feat/#8 : kakao gradle, Manifest Setting
dmp100 9f97719
[merge] setting/#4 네비게이션 세팅 to feat/#8-kakao-token
dmp100 8119c05
feat/#8 : implement kakao login data layer
dmp100 3702ffe
feat/#8 : datastore,tink setting
dmp100 6275a0a
feat/#8 : TinkEncryption, impl refactor
dmp100 3b16e24
feat/#8 : AuthLocalDataSourceImpl
dmp100 85e3f62
feat/#8 : Network module to ServiceModule
dmp100 d7ab3bb
feat/#8 : 인증 로직을 위한 DI 설정 및 TinkEncryption 모듈 추가
dmp100 ac6ab4f
feat/#8 : Kakao Login UI & Navigation
dmp100 7c7e505
refactor/#8 : add Timber, suspendRunCatching
dmp100 1042987
[Merge] feat/#12 SnackBar to feat/#8-kakao-token
dmp100 525f190
refactor/#8 : 주소랑 BaseResponse 수정
dmp100 94176d1
refactor/#8 : move to common:sercurity
dmp100 f5c74fb
refactor/#8 : dir sercurity
dmp100 17c6265
refactor/#8 : TinkEncryption을 CryptoManager 인터페이스로 리팩토링
dmp100 dc0ce56
refactor/#8 : AuthLocalDataSourceImpl DataStore 싱글톤 구조 개선
dmp100 bc217c7
refactor/#8 : encryptedToken 빠진거 추가
dmp100 daaaff0
refactor/#8 : add black color to KakaoLoginBtn
dmp100 dcbcc3a
efactor/#8 : naming KakaoLoginScreen
dmp100 a7ecf2e
refactor/#8 : 카카오 로그인 연동 및 Context 의존성 구조 개선
dmp100 fdd9d7b
refactor/#8 : TinkCryptoManager 책임 분리
dmp100 257204e
refactor/#8 : naming KaKao -> AuthParent
dmp100 80b0d7d
refactor/#8 : move to auth/parent
dmp100 bce3fc0
refactor/#8 : delete object{}
dmp100 bd58645
refactor/#8 : 상태로 네비게이션 관리하기
dmp100 7cc7caa
refactor/#8 : naming ParentLoginViewModel
dmp100 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -67,4 +67,4 @@ object NetworkModule { | |
| .addConverterFactory(converterFactory) | ||
| .client(client) | ||
| .build() | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| package com.kiero.core.security | ||
|
|
||
| interface CryptoManager { | ||
| fun encrypt(plaintext: String): String | ||
| fun decrypt(ciphertext: String): String | ||
| } |
4 changes: 4 additions & 0 deletions
4
app/src/main/java/com/kiero/core/security/EncryptionException.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| package com.kiero.core.security | ||
|
|
||
| class EncryptionException(message: String, cause: Throwable? = null) : | ||
| Exception(message, cause) |
92 changes: 92 additions & 0 deletions
92
app/src/main/java/com/kiero/core/security/TinkCryptoManager.kt
dmp100 marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| package com.kiero.core.security | ||
|
|
||
| import android.content.Context | ||
| import android.util.Base64 | ||
| import com.google.crypto.tink.Aead | ||
| import com.google.crypto.tink.InsecureSecretKeyAccess | ||
| import com.google.crypto.tink.KeysetHandle | ||
| import com.google.crypto.tink.TinkJsonProtoKeysetFormat | ||
| import com.google.crypto.tink.aead.AeadConfig | ||
| import com.google.crypto.tink.aead.PredefinedAeadParameters | ||
| import dagger.hilt.android.qualifiers.ApplicationContext | ||
| import jakarta.inject.Inject | ||
| import java.io.File | ||
| import java.nio.charset.StandardCharsets | ||
|
|
||
|
|
||
| class TinkCryptoManager @Inject constructor( | ||
| @param:ApplicationContext private val context: Context | ||
| ) : CryptoManager { | ||
|
|
||
| private val aead: Aead | ||
|
|
||
| init { | ||
| try { | ||
| AeadConfig.register() | ||
|
|
||
| val keysetFile = File(context.filesDir, KEYSET_FILENAME) | ||
| val keysetHandle = if (keysetFile.exists()) { | ||
| loadKeysetHandle(keysetFile) | ||
| } else { | ||
| generateAndSaveKeysetHandle(keysetFile) | ||
| } | ||
|
|
||
| aead = keysetHandle.getPrimitive(Aead::class.java) | ||
| } catch (e: Exception) { | ||
| throw IllegalStateException("암호화 초기화 실패", e) | ||
| } | ||
| } | ||
|
|
||
| private fun generateAndSaveKeysetHandle(keysetFile: File): KeysetHandle { | ||
| return try { | ||
| val keysetHandle = KeysetHandle.generateNew(PredefinedAeadParameters.AES256_GCM) | ||
| val keysetJson = TinkJsonProtoKeysetFormat.serializeKeyset( | ||
| keysetHandle, | ||
| InsecureSecretKeyAccess.get() | ||
| ) | ||
| keysetFile.writeText(keysetJson) | ||
| keysetHandle | ||
| } catch (e: Exception) { | ||
| throw EncryptionException("키셋 생성 및 저장 실패", e) | ||
| } | ||
| } | ||
|
|
||
| private fun loadKeysetHandle(keysetFile: File): KeysetHandle { | ||
| return try { | ||
| val keysetJson = keysetFile.readText() | ||
| TinkJsonProtoKeysetFormat.parseKeyset( | ||
| keysetJson, | ||
| InsecureSecretKeyAccess.get() | ||
| ) | ||
| } catch (e: Exception) { | ||
| throw EncryptionException("키셋 로드 실패", e) | ||
| } | ||
| } | ||
|
|
||
| override fun encrypt(plaintext: String): String { | ||
| return try { | ||
| val plaintextBytes = plaintext.toByteArray(CHARSET) | ||
| val encryptedBytes = aead.encrypt(plaintextBytes, ASSOCIATED_DATA) | ||
| Base64.encodeToString(encryptedBytes, BASE64_FLAGS) | ||
| } catch (e: Exception) { | ||
| throw EncryptionException("암호화 실패", e) | ||
| } | ||
| } | ||
|
|
||
| override fun decrypt(ciphertext: String): String { | ||
| return try { | ||
| val encryptedBytes = Base64.decode(ciphertext, BASE64_FLAGS) | ||
| val decryptedBytes = aead.decrypt(encryptedBytes, ASSOCIATED_DATA) | ||
| String(decryptedBytes, CHARSET) | ||
| } catch (e: Exception) { | ||
| throw EncryptionException("복호화 실패", e) | ||
| } | ||
| } | ||
|
|
||
| companion object { | ||
| private const val KEYSET_FILENAME = "kiero_tink_keyset.json" | ||
| private val CHARSET = StandardCharsets.UTF_8 | ||
| private const val BASE64_FLAGS = Base64.NO_WRAP | ||
| private val ASSOCIATED_DATA = null | ||
| } | ||
| } |
24 changes: 24 additions & 0 deletions
24
app/src/main/java/com/kiero/core/security/di/SecurityModule.kt
dmp100 marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| package com.kiero.core.security.di | ||
|
|
||
| import android.content.Context | ||
| import com.kiero.core.security.CryptoManager | ||
| import com.kiero.core.security.TinkCryptoManager | ||
| 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 SecurityModule { | ||
|
|
||
| @Provides | ||
| @Singleton | ||
| fun providesCryptoManager( | ||
| @ApplicationContext context: Context | ||
| ): CryptoManager { | ||
| return TinkCryptoManager(context) | ||
| } | ||
| } |
16 changes: 16 additions & 0 deletions
16
app/src/main/java/com/kiero/data/auth/local/datasource/AuthLocalDataSource.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package com.kiero.data.auth.local.datasource | ||
|
|
||
|
|
||
| interface AuthLocalDataSource { | ||
|
|
||
| // @param token JWT 액세스 토큰 | ||
| suspend fun saveAccessToken(token: String) | ||
| // @param token JWT 리프레시 토큰 | ||
| suspend fun saveRefreshToken(token: String) | ||
| // @return 저장된 액세스 토큰, 없으면 null | ||
| suspend fun getAccessToken(): String? | ||
| // @return 저장된 리프레시 토큰, 없으면 null | ||
| suspend fun getRefreshToken(): String? | ||
| // 토큰 삭제. | ||
| suspend fun clearTokens() | ||
| } |
78 changes: 78 additions & 0 deletions
78
app/src/main/java/com/kiero/data/auth/local/datasourceimpl/AuthLocalDataSourceImpl.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| package com.kiero.data.auth.local.datasourceimpl | ||
|
|
||
| import android.content.Context | ||
| import androidx.datastore.core.DataStore | ||
| import androidx.datastore.preferences.core.Preferences | ||
| import androidx.datastore.preferences.core.edit | ||
| import androidx.datastore.preferences.core.stringPreferencesKey | ||
| import androidx.datastore.preferences.preferencesDataStore | ||
| import com.kiero.core.common.util.suspendRunCatching | ||
| import com.kiero.core.security.CryptoManager | ||
| import com.kiero.data.auth.local.datasource.AuthLocalDataSource | ||
| import dagger.hilt.android.qualifiers.ApplicationContext | ||
| import kotlinx.coroutines.flow.first | ||
| import kotlinx.coroutines.flow.map | ||
| import timber.log.Timber | ||
| import javax.inject.Inject | ||
|
|
||
| private const val DATASTORE_NAME = "kiero_auth_datastore" | ||
| private val KEY_ACCESS_TOKEN = stringPreferencesKey("access_token") | ||
| private val KEY_REFRESH_TOKEN = stringPreferencesKey("refresh_token") | ||
|
|
||
| private val Context.authDataStore: DataStore<Preferences> by preferencesDataStore( | ||
| name = DATASTORE_NAME | ||
| ) | ||
|
|
||
| class AuthLocalDataSourceImpl @Inject constructor( | ||
| @param:ApplicationContext private val context: Context, | ||
| private val cryptoManager: CryptoManager, | ||
| ) : AuthLocalDataSource { | ||
|
|
||
| override suspend fun saveAccessToken(token: String) { | ||
| suspendRunCatching { | ||
| val encryptedToken = cryptoManager.encrypt(token) | ||
| context.authDataStore.edit { it[KEY_ACCESS_TOKEN] = encryptedToken } | ||
| }.onFailure { throwable -> | ||
| Timber.e(throwable, "AccessToken 저장 실패") | ||
| } | ||
| } | ||
|
|
||
| override suspend fun saveRefreshToken(token: String) { | ||
| suspendRunCatching { | ||
| val encryptedToken = cryptoManager.encrypt(token) | ||
| context.authDataStore.edit { it[KEY_REFRESH_TOKEN] = encryptedToken } | ||
| }.onFailure { throwable -> | ||
| Timber.e(throwable, "RefreshToken 저장 실패") | ||
| } | ||
| } | ||
|
|
||
| override suspend fun getAccessToken(): String? { | ||
| return suspendRunCatching { | ||
| val encryptedToken = context.authDataStore.data | ||
| .map { it[KEY_ACCESS_TOKEN] } | ||
| .first() | ||
| encryptedToken?.let { cryptoManager.decrypt(it) } | ||
| }.onFailure { throwable -> | ||
| Timber.e(throwable, "AccessToken 로드 실패") | ||
| }.getOrNull() | ||
| } | ||
|
|
||
| override suspend fun getRefreshToken(): String? { | ||
| return suspendRunCatching { | ||
| val encryptedToken = context.authDataStore.data | ||
| .map { it[KEY_REFRESH_TOKEN] } | ||
| .first() | ||
| encryptedToken?.let { cryptoManager.decrypt(it) } | ||
| }.onFailure { throwable -> | ||
| Timber.e(throwable, "RefreshToken 로드 실패") | ||
| }.getOrNull() | ||
| } | ||
|
|
||
| override suspend fun clearTokens() { | ||
| suspendRunCatching { | ||
| context.authDataStore.edit { it.clear() } | ||
| }.onFailure { throwable -> | ||
| Timber.e(throwable, "토큰 삭제 실패") | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.