Swapnil Musale
11/16/2024, 9:22 AMclass AndroidNetworkGateway(
private val debug: Boolean,
private val interceptors: List<Interceptor>,
private val networkInterceptor: List<Interceptor>,
private val aesEncryptionManager: AesEncryptionManager,
) : INetworkGateway {
override val client: HttpClient
get() = HttpClient(OkHttp) {
engine {
config {
callTimeout(30, TimeUnit.SECONDS)
connectTimeout(30, TimeUnit.SECONDS)
readTimeout(30, TimeUnit.SECONDS)
writeTimeout(30, TimeUnit.SECONDS)
}
interceptors.forEach { addInterceptor(it) }
networkInterceptor.forEach { addNetworkInterceptor(it) }
}
install(ContentNegotiation) {
json(BaseApi.networkJsonParser)
}
install(Logging) {
level = if (debug) LogLevel.ALL else LogLevel.NONE
}
install(ApiEncryption) {
encryptionManager = aesEncryptionManager
}
}
}
ApiEncryption
class ApiEncryption(private val aesEncryptionManager: AesEncryptionManager) {
class Config {
var encryptionManager: AesEncryptionManager? = null
}
companion object : HttpClientPlugin<Config, ApiEncryption> {
override val key: AttributeKey<ApiEncryption> = AttributeKey(name = "ApiEncryption")
override fun prepare(block: Config.() -> Unit): ApiEncryption {
val config = Config().apply(block)
val aesEncryptionManager = config.encryptionManager
?: throw IllegalArgumentException("AesEncryptionManager must be provided")
return ApiEncryption(aesEncryptionManager)
}
@OptIn(ExperimentalStdlibApi::class, InternalAPI::class)
override fun install(plugin: ApiEncryption, scope: HttpClient) {
val aesEncryptionManager = plugin.aesEncryptionManager
// Encrypt API Request
scope.requestPipeline.intercept(phase = HttpRequestPipeline.Before) {
if (this.context.body !is EmptyContent) {
val originalRequest = this.context.body.toString()
val encryptedRequest =
aesEncryptionManager.encrypt(plainText = originalRequest)
proceedWith(subject = encryptedRequest)
} else {
proceed()
}
}
// Decrypt API Response
scope.responsePipeline.intercept(phase = HttpResponsePipeline.Receive) { (info, body) ->
try {
val encryptedResponse = this.context.response.content.readUTF8Line()
if (encryptedResponse?.isEncryptedResponse() == true) {
aesEncryptionManager.decrypt(
cipherText = encryptedResponse.data?.hexToByteArray()!!,
ivByteArray = encryptedResponse.iv?.hexToByteArray()!!,
).also { decryptedResponse ->
proceedWith(
subject = HttpResponseContainer(
expectedType = info,
response = buildPacket {
writeText(text = decryptedResponse)
},
),
)
}
} else {
proceedWith(
subject = HttpResponseContainer(
expectedType = info,
response = body,
),
)
}
} catch (exception: Exception) {
exception.printStackTrace()
}
}
}
}
}
As of now chucker intercepting a app encrypted request and server encrypted response in Chucker UI.
I want to display decrypted response as well (will be available via ktor HttpResponsePipeline.After)
Is there any plan to support this feature request? or Any way to do this at this momentsSwapnil Musale
11/16/2024, 10:50 AMclass ApiResponseInterceptor : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val request: Request = chain.request()
val response: Response = chain.proceed(request)
if (response.code == 200) {
val jsonObject = JSONObject()
try {
jsonObject.put("code", 200)
jsonObject.put("status", "OK")
jsonObject.put("message", "Successful")
val contentType = response.body!!.contentType()
val body: ResponseBody = ResponseBody.create(contentType, jsonObject.toString())
return response.newBuilder().body(body).build()
} catch (e: JSONException) {
e.printStackTrace()
}
} else if (response.code == 403) {
}
return response
}
}
But still Chucker showing original server response in UIColton Idle
11/26/2024, 11:41 PM