-
Notifications
You must be signed in to change notification settings - Fork 3
[Feat] 구글 소셜 로그인 구현 #78
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
Changes from all commits
c56e4fe
95ca8c8
e80c3a5
a4c5c28
48014b0
e00e585
cdff7a0
9a67f61
56144a0
e78a120
9833a07
5b5b7e3
9b4c045
d846745
fe5f3bb
7befae5
f39127a
5a5c765
d8310aa
fafe4d2
8638197
b609cc2
7f6cee5
09a9f98
b116fd1
305bb85
7c199d5
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.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| { | ||
| "project_info": { | ||
| "project_number": "353417813537", | ||
| "project_id": "thip-3a698", | ||
| "storage_bucket": "thip-3a698.firebasestorage.app" | ||
| }, | ||
| "client": [ | ||
| { | ||
| "client_info": { | ||
| "mobilesdk_app_id": "1:353417813537:android:69029c2bc957df7fab4d60", | ||
| "android_client_info": { | ||
| "package_name": "com.texthip.thip" | ||
| } | ||
| }, | ||
| "oauth_client": [ | ||
| { | ||
| "client_id": "353417813537-lovs0p2tb9kjnjlp493a7098ov0cb2bu.apps.googleusercontent.com", | ||
| "client_type": 1, | ||
| "android_info": { | ||
| "package_name": "com.texthip.thip", | ||
| "certificate_hash": "99315de9382f8b2903131eb4ae926a4739803ef1" | ||
| } | ||
| }, | ||
| { | ||
| "client_id": "353417813537-ck9g1v0qprlb5nf4dvasinim403eng0f.apps.googleusercontent.com", | ||
| "client_type": 3 | ||
| } | ||
| ], | ||
| "api_key": [ | ||
| { | ||
| "current_key": "AIzaSyCFzpbeT-8JQCGxiSKuVXMvcNNYFtl6Fuo" | ||
| } | ||
| ], | ||
|
Comment on lines
+29
to
+33
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. 💡 Verification agent ❓ Verification inconclusive공개 저장소에 Firebase API Key가 그대로 커밋됨 — 키 제한 및 회수(rotate) 필요 이 파일은 보통 커밋되기도 하지만, 레포가 공개(public)라면 남용 위험이 있습니다. 최소한 다음 조치가 필요합니다:
원하시면 CI에서 flavor별 google-services.json을 주입하도록 스크립트/가이드를 드리겠습니다. 긴급: 공개 저장소에 노출된 Firebase API Key 제한 및 회수 필요 app/google-services.json (29-33행)에 아래와 같은 API Key가 그대로 커밋되어 있습니다. 노출된 키는 악용될 위험이 있으므로 즉시 조치해 주세요:
필요하시면 CI에서 flavor별 json을 주입하는 스크립트/가이드를 제공해 드리겠습니다. 🤖 Prompt for AI Agents |
||
| "services": { | ||
| "appinvite_service": { | ||
| "other_platform_oauth_client": [ | ||
| { | ||
| "client_id": "353417813537-ck9g1v0qprlb5nf4dvasinim403eng0f.apps.googleusercontent.com", | ||
| "client_type": 3 | ||
| } | ||
| ] | ||
| } | ||
| } | ||
| } | ||
| ], | ||
| "configuration_version": "1" | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,21 @@ | ||
| package com.texthip.thip | ||
|
|
||
| import com.kakao.sdk.common.KakaoSdk | ||
| import android.app.Application | ||
| import dagger.hilt.android.HiltAndroidApp | ||
| import com.texthip.thip.BuildConfig | ||
|
|
||
|
|
||
| @HiltAndroidApp | ||
| class ThipApplication : Application() | ||
| class ThipApplication : Application(){ | ||
| override fun onCreate() { | ||
| super.onCreate() | ||
|
|
||
| // 카카오 SDK 초기화 | ||
| try { | ||
| KakaoSdk.init(this, BuildConfig.NATIVE_APP_KEY) | ||
| }catch (e: Exception){ | ||
| e.printStackTrace() | ||
| } | ||
| } | ||
| } | ||
|
Comment on lines
+10
to
+21
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. 💡 Verification agent 🧩 Analysis chainKakao SDK 초기화: 광범위한 예외 삼키기 대신 키 검증 + 명확한 로깅 현재 적용 제안(diff): - // 카카오 SDK 초기화
- try {
- KakaoSdk.init(this, BuildConfig.NATIVE_APP_KEY)
- }catch (e: Exception){
- e.printStackTrace()
- }
+ // 카카오 SDK 초기화
+ if (BuildConfig.NATIVE_APP_KEY.isBlank()) {
+ android.util.Log.e("ThipApplication", "KAKAO NATIVE_APP_KEY is missing. Kakao SDK initialization skipped.")
+ } else {
+ KakaoSdk.init(this, BuildConfig.NATIVE_APP_KEY)
+ }검증 포인트:
아래 스크립트를 실행해 🏁 Script executed: #!/bin/bash
# 1. build.gradle에서 BuildConfig 필드로 선언된 NATIVE_APP_KEY 위치 확인
rg "buildConfigField.*NATIVE_APP_KEY" -n
# 2. 프로젝트 전반에서 NATIVE_APP_KEY 사용 위치 확인 (예: KakaoSdk.init 호출 외)
rg "NATIVE_APP_KEY" -n
# 3. AndroidManifest.xml에서 com.kakao.sdk.AppKey 메타데이터 선언 확인
rg "com.kakao.sdk.AppKey" -nLength of output: 806 카카오 SDK 초기화: 키 검증 후 명확한 로깅으로 예외 처리 개선 대상 파일
제안하는 diff: @@ -13,9 +13,12 @@ class ThipApplication : Application(){
- // 카카오 SDK 초기화
- try {
- KakaoSdk.init(this, BuildConfig.NATIVE_APP_KEY)
- } catch (e: Exception) {
- e.printStackTrace()
- }
+ // 카카오 SDK 초기화: 키 검증 후 초기화
+ val kakaoKey = BuildConfig.NATIVE_APP_KEY
+ if (kakaoKey.isBlank()) {
+ Log.e("ThipApplication", "KAKAO NATIVE_APP_KEY가 설정되지 않았습니다. SDK 초기화를 건너뜁니다.")
+ } else {
+ KakaoSdk.init(this, kakaoKey)
+ }이렇게 변경하면 설정 누락 시 Silent Fail을 방지하고, 운영 환경에서 문제 원인을 빠르게 파악할 수 있습니다. 🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| package com.texthip.thip.data.manager | ||
|
|
||
| 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 dagger.hilt.android.qualifiers.ApplicationContext | ||
| import kotlinx.coroutines.flow.Flow | ||
| import kotlinx.coroutines.flow.map | ||
| import javax.inject.Inject | ||
| import javax.inject.Singleton | ||
|
|
||
| @Singleton | ||
| class TokenManager @Inject constructor( | ||
| @ApplicationContext private val context: Context | ||
| ) { | ||
| private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "thip_auth_tokens") | ||
|
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 DataStore 위임 프로퍼티는 파일 top-level로 옮기세요 (싱글 인스턴스 보장 및 메모리 누수 방지). Jetpack DataStore 권장사항은 Context 확장 위임 프로퍼티를 파일 최상위(top-level)에 두는 것입니다. 현재 클래스 내부에 선언되어 있어도 싱글톤일 때는 동작하지만, 유지보수성과 안전성 측면에서 top-level로 이동하는 것이 좋습니다. 아래 diff로 클래스 내부 사용처를 - private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "thip_auth_tokens")
+ // moved to top-level: use `context.authDataStore` instead
@@
- context.dataStore.edit { prefs ->
+ context.authDataStore.edit { prefs ->
prefs[APP_TOKEN_KEY] = token
}
@@
- return context.dataStore.data.map { prefs ->
+ return context.authDataStore.data.map { prefs ->
prefs[APP_TOKEN_KEY]
}
@@
- context.dataStore.edit { prefs ->
+ context.authDataStore.edit { prefs ->
prefs.remove(APP_TOKEN_KEY)
}클래스 외부(파일 상단)에 아래 top-level 확장 프로퍼티를 추가하세요: // 파일 상단 (클래스 외부)
val Context.authDataStore: DataStore<Preferences> by preferencesDataStore(name = "thip_auth_tokens")Also applies to: 28-31, 35-37, 42-44 🤖 Prompt for AI Agents |
||
|
|
||
| companion object { | ||
| //토큰저장에 사용되는 키 | ||
| private val APP_TOKEN_KEY = stringPreferencesKey("app_token") | ||
| } | ||
|
|
||
| //토큰 저장 | ||
| suspend fun saveToken(token: String) { | ||
| context.dataStore.edit { prefs -> | ||
| prefs[APP_TOKEN_KEY] = token | ||
| } | ||
| } | ||
|
|
||
| //저장된 토큰을 Flow 형태로 불러옴 | ||
| fun getToken(): Flow<String?> { | ||
| return context.dataStore.data.map { prefs -> | ||
| prefs[APP_TOKEN_KEY] | ||
| } | ||
| } | ||
|
Comment on lines
+33
to
+38
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 DataStore 읽기 시 IOException 처리를 추가해 앱 크래시를 방지하세요. DataStore의 - fun getToken(): Flow<String?> {
- return context.dataStore.data.map { prefs ->
- prefs[APP_TOKEN_KEY]
- }
- }
+ fun getToken(): Flow<String?> {
+ return context.authDataStore.data
+ .catch { e ->
+ if (e is IOException) emit(emptyPreferences()) else throw e
+ }
+ .map { prefs -> prefs[APP_TOKEN_KEY] }
+ }추가 import가 필요합니다(파일 import 섹션에 추가): import androidx.datastore.preferences.core.emptyPreferences
import kotlinx.coroutines.flow.catch
import java.io.IOException🤖 Prompt for AI Agents
Comment on lines
+33
to
+38
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 DataStore 접근 시 예외 처리(catch) 추가 권장 Preferences DataStore는 I/O 예외로 플로우가 취소될 수 있습니다. 예외를 처리해 기본값을 반환하도록 하면 안정성이 올라갑니다. - fun getToken(): Flow<String?> {
- return context.dataStore.data.map { prefs ->
- prefs[APP_TOKEN_KEY]
- }
- }
+ fun getToken(): Flow<String?> {
+ return context.dataStore.data
+ .catch { e ->
+ if (e is IOException) emit(emptyPreferences()) else throw e
+ }
+ .map { prefs -> prefs[APP_TOKEN_KEY] }
+ }추가로 필요한 import:
🤖 Prompt for AI Agents |
||
|
|
||
| //저장된 토큰 삭제 (로그아웃 시?) | ||
| suspend fun deleteToken() { | ||
| context.dataStore.edit { prefs -> | ||
| prefs.remove(APP_TOKEN_KEY) | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package com.texthip.thip.data.model.auth.request | ||
| import kotlinx.serialization.SerialName | ||
| import kotlinx.serialization.Serializable | ||
|
|
||
| @Serializable | ||
| data class AuthRequest( | ||
| @SerialName("oauth2Id") val oauth2Id: String | ||
| ) | ||
|
Comment on lines
+5
to
+8
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. UID 단독 전송은 위변조 위험 — 서버 검증용 토큰(idToken/serverAuthCode) 포함 권장 현재 요청 스키마가 oauth2Id(예: “google_”)만 담습니다. 클라이언트가 임의 UID를 조작해 전송할 수 있어, 서버는 사용자 신원을 검증할 수 없습니다. 최소 한 가지 검증 가능한 증거를 추가하세요:
예시 스키마 제안: @Serializable
data class AuthRequest(
- @SerialName("oauth2Id") val oauth2Id: String
+ @SerialName("oauth2Id") val oauth2Id: String,
+ @SerialName("provider") val provider: String, // "google" | "kakao" 등
+ @SerialName("idToken") val idToken: String? = null,
+ @SerialName("serverAuthCode") val serverAuthCode: String? = null
)서버가 검증을 수행하지 않으면 인증 우회 취약점이 됩니다. 🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package com.texthip.thip.data.model.auth.response | ||
|
|
||
| import kotlinx.serialization.SerialName | ||
| import kotlinx.serialization.Serializable | ||
|
|
||
| @Serializable | ||
| data class AuthResponse( | ||
| @SerialName("token") val token: String, | ||
| @SerialName("isNewUser") val isNewUser: Boolean | ||
| ) |
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.
💡 Verification agent
🧩 Analysis chain
Firebase BOM / Play Services Auth 최신화 여부 확인
보안/호환성 차원에서 최신 안정 버전 사용을 권장합니다. 현재 지정된 버전이 최신인지 확인해 주세요.
🌐 Web query:
💡 Result:
Details and sources:
Citations:
Play Services Auth 라이브러리 버전 업데이트 필요
app/build.gradle.kts(라인 107–109)34.1.0)은 최신 안정 버전이지만,com.google.android.gms:play-services-auth는 현재21.2.0으로 설정되어 있습니다.수정 예시:
📝 Committable suggestion
🤖 Prompt for AI Agents