Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 28 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import org.gradle.kotlin.dsl.implementation
import java.util.Properties

plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose)
alias(libs.plugins.kotlin.serialization)
id("com.google.dagger.hilt.android")
kotlin("kapt")
}

val properties = Properties().apply {
load(project.rootProject.file("local.properties").inputStream())
}
Comment on lines +12 to 14
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

local.properties 파일 존재 여부를 검증하세요.

local.properties 파일이 존재하지 않을 경우 빌드가 실패할 수 있습니다.

다음 스크립트로 파일 존재 여부와 BASE_URL 설정을 확인해주세요:


🏁 Script executed:

#!/bin/bash
# local.properties 파일과 BASE_URL 설정 확인
if [ -f "local.properties" ]; then
    echo "local.properties 파일 존재함"
    grep "BASE_URL" local.properties || echo "BASE_URL 설정이 없습니다"
else
    echo "local.properties 파일이 존재하지 않습니다"
fi

# .gitignore에서 local.properties 제외 여부 확인
grep -n "local.properties" .gitignore || echo "local.properties가 .gitignore에 없습니다"

Length of output: 178


local.properties 파일 누락 및 예시 파일(example) 추가 필요

현재 루트 디렉토리에 local.properties 파일이 없으며, .gitignore/local.propertieslocal.properties가 모두 등록되어 있습니다.
이대로라면 Gradle에서 project.rootProject.file("local.properties")를 로드할 때 빌드가 실패합니다.

해야 할 작업:

  • 루트에 local.properties.example (또는 local.properties.template) 파일을 추가하고, README 등에 실제 local.properties 생성 및 BASE_URL 설정 방법을 문서화하세요.
  • app/build.gradle.kts에서 파일이 없을 경우 기본값을 설정하거나 로드 구문을 감싸서 빌드 실패를 방지하는 처리(.exists() 체크 등)를 추가하세요.

대략적인 코드 예시:

 val properties = Properties().apply {
-    load(project.rootProject.file("local.properties").inputStream())
+    val propFile = project.rootProject.file("local.properties")
+    if (propFile.exists()) {
+        load(propFile.inputStream())
+    } else {
+        logger.warn("local.properties not found: using default BASE_URL")
+        setProperty("BASE_URL", "https://default.example.com")
+    }
 }
🤖 Prompt for AI Agents
In app/build.gradle.kts around lines 12 to 14, the code loads local.properties
without checking if the file exists, causing build failures if the file is
missing. To fix this, first add a local.properties.example file in the root
directory with example settings and document how to create the actual
local.properties in the README. Then, modify the build.gradle.kts to check if
local.properties exists before loading it, and provide default values or skip
loading if it does not exist to prevent build errors.


android {
Expand All @@ -19,6 +25,8 @@ android {
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 어떤 뜻인가요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

local properties에서 BASE_URL을 가져와서 build config에 상수화하는 역할입니닷 ! base url을 드러내지 않기 위해서 이런 코드를 작성했습니닷

buildConfigField("String", "BASE_URL", "\"${properties["BASE_URL"]}\"")
}

buildTypes {
Expand All @@ -39,6 +47,7 @@ android {
}
buildFeatures {
compose = true
buildConfig = true
}
}

Expand Down Expand Up @@ -67,4 +76,22 @@ dependencies {
androidTestImplementation(libs.androidx.ui.test.junit4)
debugImplementation(libs.androidx.ui.tooling)
debugImplementation(libs.androidx.ui.test.manifest)

// Hilt
implementation(libs.hilt.android)
kapt(libs.hilt.android.compiler)
implementation(libs.androidx.hilt.navigation.compose)

// Retrofit
implementation(libs.retrofit)
implementation(libs.converter.gson)
implementation(libs.retrofit.kotlin.serialization.converter)

// OkHttp
implementation(libs.okhttp)
implementation(libs.logging.interceptor)
}
Comment on lines +81 to +93
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

의존성 버전을 확인하세요.

Hilt, Retrofit, OkHttp 라이브러리들의 버전 호환성과 최신 보안 패치 적용 여부를 확인하는 것이 좋습니다.

라이브러리 최신 버전을 확인해주세요:


🌐 Web query:

Dagger Hilt, Retrofit, OkHttp의 최신 안정 버전과 보안 권고사항을 알려주세요

💡 Result:

안녕하세요! Dagger Hilt, Retrofit, OkHttp의 최신 안정 버전과 보안 권고사항에 대해 알려드리겠습니다.

최신 안정 버전:

  • Dagger Hilt: 최신 안정 버전은 2.48입니다.
  • Retrofit: 최신 안정 버전은 2.9.0입니다.
  • OkHttp: 최신 안정 버전은 4.9.3입니다.

이러한 버전들은 각 라이브러리의 공식 문서나 GitHub 저장소에서 확인하실 수 있습니다.

보안 권고사항:

  1. 의존성 최신 상태 유지: 보안 취약점을 최소화하기 위해 사용하는 라이브러리의 버전을 최신 상태로 유지하는 것이 중요합니다.

  2. HTTPS 사용: 네트워크 통신 시 HTTPS를 사용하여 데이터 전송의 보안을 강화하세요.

  3. 네트워크 보안 설정: 안드로이드 앱의 network_security_config.xml 파일을 활용하여 보안 정책을 설정하고, 신뢰할 수 있는 도메인만 허용하도록 구성하세요.

  4. 인증서 검증 강화: 서버와의 통신 시 SSL/TLS 인증서를 철저히 검증하여 중간자 공격을 방지하세요.

  5. 의존성 주입 시 주의: Dagger Hilt를 사용할 때, 의존성 주입 대상의 범위를 명확히 정의하고, 필요하지 않은 의존성은 주입하지 않도록 주의하세요.

이러한 권고사항을 따르면 앱의 보안을 강화할 수 있습니다.


의존성 버전 업데이트 및 보안 강화 권고

아래 라이브러리들이 최신 안정 버전인지 확인하고, 필요 시 버전을 상향 조정해주세요. 또한 보안 권고사항을 참고해 네트워크 통신 설정을 강화하시기 바랍니다.

  • Hilt
    – 최신 안정 버전: 2.48
    libs.hilt.android(및 관련 kapt, navigation.compose) 설정이 2.48 이상인지 확인 후 업데이트
  • Retrofit
    – 최신 안정 버전: 2.9.0
    libs.retrofit, libs.converter.gson, libs.retrofit.kotlin.serialization.converter 버전 검토 및 상향
  • OkHttp
    – 최신 안정 버전: 4.9.3
    libs.okhttp, libs.logging.interceptor 버전 검토 및 상향

보안 권고사항

  • HTTPS 프로토콜 사용 여부 확인
  • network_security_config.xml 에서 신뢰할 도메인만 허용하도록 설정
  • SSL/TLS 인증서 유효성 검증 강화
  • Dagger Hilt 의존성 주입 대상(scope) 명확화 및 불필요 주입 최소화
🤖 Prompt for AI Agents
In app/build.gradle.kts around lines 81 to 93, verify and update the versions of
Hilt, Retrofit, and OkHttp dependencies to at least Hilt 2.48, Retrofit 2.9.0,
and OkHttp 4.9.3 respectively by adjusting the version references in the libs
configuration. Additionally, review your network security settings to ensure
HTTPS is enforced, restrict trusted domains in network_security_config.xml,
strengthen SSL/TLS certificate validation, and refine Dagger Hilt dependency
injection scopes to minimize unnecessary injections.


kapt {
correctErrorTypes = true
}
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools">

<application
android:name=".ThipApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/texthip/thip/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import androidx.compose.ui.tooling.preview.Preview
import com.texthip.thip.ui.theme.ThipTheme
import com.texthip.thip.ui.theme.ThipTheme.colors
import com.texthip.thip.ui.theme.ThipTheme.typography
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/java/com/texthip/thip/ThipApplication.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.texthip.thip

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class ThipApplication : Application()
69 changes: 69 additions & 0 deletions app/src/main/java/com/texthip/thip/data/di/NetworkModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.texthip.thip.data.di

import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import com.texthip.thip.BuildConfig
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import java.util.concurrent.TimeUnit
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@OptIn(ExperimentalSerializationApi::class)
@Provides
@Singleton
fun provideJson(): Json =
Json {
isLenient = true // 유연한 JSON 구분 허용
prettyPrint = true // 출력 JSON 을 예쁘게 들여쓰기해서 가독성을 높임
encodeDefaults = true // 파라미터의 기본값(default) 을 JSON 으로 인코딩
explicitNulls = false // null 값을 명시적으로 표시하지 않음
ignoreUnknownKeys = true // JSON 에 정의하지 않은 키가 있어도 무시하고 파싱
}

@Provides
@Singleton
fun providesOkHttpClient(
loggingInterceptor: HttpLoggingInterceptor,
// authInterceptor: AuthInterceptor,
// authAuthenticator: TokenAuthenticator
): OkHttpClient =
OkHttpClient.Builder().apply {
connectTimeout(10, TimeUnit.SECONDS)
writeTimeout(10, TimeUnit.SECONDS)
readTimeout(10, TimeUnit.SECONDS)
addInterceptor(loggingInterceptor)
// addInterceptor(authInterceptor)
// authenticator(authAuthenticator)
}.build()

@Provides
@Singleton
fun providesLoggingInterceptor(): HttpLoggingInterceptor =
HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
Comment on lines +51 to +54
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

로깅 레벨을 환경에 따라 조정하세요.

현재 BODY 레벨로 설정되어 있어 프로덕션 환경에서 민감한 데이터가 로그에 노출될 수 있습니다.

BuildConfig를 활용해 디버그/릴리즈 환경에 따라 로깅 레벨을 조정하세요:

 fun providesLoggingInterceptor(): HttpLoggingInterceptor =
     HttpLoggingInterceptor().apply {
-        level = HttpLoggingInterceptor.Level.BODY
+        level = if (BuildConfig.DEBUG) {
+            HttpLoggingInterceptor.Level.BODY
+        } else {
+            HttpLoggingInterceptor.Level.NONE
+        }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fun providesLoggingInterceptor(): HttpLoggingInterceptor =
HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
}
fun providesLoggingInterceptor(): HttpLoggingInterceptor =
HttpLoggingInterceptor().apply {
level = if (BuildConfig.DEBUG) {
HttpLoggingInterceptor.Level.BODY
} else {
HttpLoggingInterceptor.Level.NONE
}
}
🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/data/di/NetworkModule.kt around lines 51
to 54, the HttpLoggingInterceptor is set to log at BODY level unconditionally,
which risks exposing sensitive data in production. Modify the code to check the
build environment using BuildConfig and set the logging level to BODY only in
debug builds, while setting it to NONE or a less verbose level in release builds
to protect sensitive information.


@Provides
@Singleton
fun providesRetrofit(
json: Json,
okHttpClient: OkHttpClient
): Retrofit =
Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

BASE_URL 설정을 검증하세요.

BuildConfig.BASE_URL이 올바르게 설정되었는지 확인이 필요합니다.

다음 스크립트로 BASE_URL 설정을 확인해주세요:


🏁 Script executed:

#!/bin/bash
# BuildConfig 파일에서 BASE_URL 확인
fd -t f -e java "BuildConfig" --exec grep -l "BASE_URL" {} \;

Length of output: 62


🏁 Script executed:

#!/bin/bash
# 전체 코드베이스에서 BASE_URL 정의 및 사용 위치 검색
rg -n 'BASE_URL'
# build.gradle(.kts) 파일에서 buildConfigField BASE_URL 정의 확인
rg -n 'buildConfigField.*BASE_URL' -g '*.gradle' -g '*.gradle.kts'

Length of output: 399


🏁 Script executed:

#!/bin/bash
# gradle.properties 및 local.properties에서 BASE_URL 정의 여부 확인
rg -n 'BASE_URL' -g '*.properties'

Length of output: 34


BASE_URL 프로퍼티 정의 누락 확인 및 설정 필요

app/build.gradle.kts (29행)에서

buildConfigField("String", "BASE_URL", "\"${properties["BASE_URL"]}\"")

BuildConfig.BASE_URL을 설정하고 있지만, 프로젝트 루트의 gradle.propertieslocal.properties에서 해당 BASE_URL 프로퍼티가 정의되어 있지 않습니다.

해결 방안:

  • gradle.properties 또는 local.properties에 다음과 같이 BASE_URL을 추가하세요.
    BASE_URL="https://your.api.endpoint/"
  • CI/CD 환경에서 Gradle 빌드 시 -PBASE_URL=... 옵션으로 값이 전달되는지 확인하세요.
🤖 Prompt for AI Agents
In app/src/main/java/com/texthip/thip/data/di/NetworkModule.kt at line 63, the
BuildConfig.BASE_URL is used but the BASE_URL property is not defined in the
project configuration. To fix this, add the BASE_URL property with the
appropriate API endpoint URL to either gradle.properties or local.properties in
the project root, for example BASE_URL="https://your.api.endpoint/". Also ensure
that in CI/CD builds, the BASE_URL is passed as a Gradle property using the
-PBASE_URL=... option.

.addConverterFactory(
json.asConverterFactory(requireNotNull("application/json".toMediaType()))
)
.client(okHttpClient)
.build()
}
12 changes: 12 additions & 0 deletions app/src/main/java/com/texthip/thip/data/di/ServiceModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.texthip.thip.data.di

import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent

@Module
@InstallIn(SingletonComponent::class)
object ServiceModule {
// @Provides
// @Singleton
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.texthip.thip.data.model.base

fun <T> BaseResponse<T>.handleBaseResponse(): Result<T?> {
return if (isSuccess) {
Result.success(this.response)
} else {
Result.failure(
ThipApiFailureException(
code = this.code,
message = this.message
)
)
}
}

data class ThipApiFailureException(
val code: Int,
override val message: String
) : Throwable()
12 changes: 12 additions & 0 deletions app/src/main/java/com/texthip/thip/data/model/base/BaseResponse.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.texthip.thip.data.model.base

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class BaseResponse<T>(
@SerialName("isSuccess") val isSuccess: Boolean,
@SerialName("code") val code: Int,
@SerialName("message") val message: String,
@SerialName("data") val response: T? = null,
)
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.compose) apply false
id("com.google.dagger.hilt.android") version "2.57" apply false
}
22 changes: 19 additions & 3 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,24 +1,36 @@
[versions]
agp = "8.11.1"
kotlin = "2.0.21"
agp = "8.9.3"
converterGson = "3.0.0"
hiltAndroid = "2.57"
hiltNavigationCompose = "1.2.0"
kotlin = "2.2.0"
coreKtx = "1.16.0"
junit = "4.13.2"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
lifecycleRuntimeKtx = "2.8.7"
activityCompose = "1.10.1"
composeBom = "2024.09.00"
navigationCompose = "2.9.0"
loggingInterceptor = "5.1.0"
navigationCompose = "2.9.2"
foundation = "1.9.0-beta01"
lifecycleViewmodelCompose = "2.9.1"
navigationRuntimeAndroid = "2.9.0"
accompanistPager = "0.36.0"
accompanistPagerIndicators = "0.36.0"
coilCompose = "2.7.0"
kotlinxSerializationJson = "1.9.0"
okhttp = "5.1.0"
retrofit = "3.0.0"
retrofitKotlinSerializationConverter = "1.0.0"
androidxComposeNavigation = "2.8.2"

[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "hiltNavigationCompose" }
converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "converterGson" }
hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltAndroid" }
hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hiltAndroid" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
Expand All @@ -40,6 +52,10 @@ accompanist-pager = { group = "com.google.accompanist", name = "accompanist-page
accompanist-pager-indicators = { group = "com.google.accompanist", name = "accompanist-pager-indicators", version.ref = "accompanistPagerIndicators" }
coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coilCompose" }
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
logging-interceptor = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "loggingInterceptor" }
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
retrofit-kotlin-serialization-converter = { group = "com.jakewharton.retrofit", name = "retrofit2-kotlinx-serialization-converter", version.ref = "retrofitKotlinSerializationConverter" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
Expand Down