-
Notifications
You must be signed in to change notification settings - Fork 24
/
Copy pathMethodCallHandler.kt
205 lines (182 loc) · 7.25 KB
/
MethodCallHandler.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
package com.aheaditec.freerasp.handlers
import android.app.Activity
import android.content.Context
import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.aheaditec.freerasp.ScreenProtector
import com.aheaditec.freerasp.Utils
import com.aheaditec.freerasp.generated.TalsecPigeonApi
import com.aheaditec.freerasp.runResultCatching
import com.aheaditec.freerasp.toPigeon
import com.aheaditec.talsec_security.security.api.SuspiciousAppInfo
import com.aheaditec.talsec_security.security.api.Talsec
import io.flutter.Log
import io.flutter.plugin.common.BinaryMessenger
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
/**
* A method handler that creates and manages an [MethodChannel] for freeRASP methods.
*/
internal class MethodCallHandler(private val screenProtector: ScreenProtector?) : MethodCallHandler,
LifecycleEventObserver {
private var context: Context? = null
private var methodChannel: MethodChannel? = null
private var pigeonApi: TalsecPigeonApi? = null
private val backgroundHandlerThread = HandlerThread("BackgroundThread").apply { start() }
private val backgroundHandler = Handler(backgroundHandlerThread.looper)
private val mainHandler = Handler(Looper.getMainLooper())
internal var activity: Activity? = null
companion object {
private const val CHANNEL_NAME: String = "talsec.app/freerasp/methods"
}
private val sink = object : MethodSink {
override fun onMalwareDetected(packageInfo: List<SuspiciousAppInfo>) {
context?.let { context ->
val pigeonPackageInfo = packageInfo.map { it.toPigeon(context) }
pigeonApi?.onMalwareDetected(pigeonPackageInfo) { result ->
// Parse the result (which is Unit so we can ignore it) or throw an exception
// Exceptions are translated to Flutter errors automatically
result.getOrElse {
Log.e("MethodCallHandlerSink", "Result ended with failure")
throw it
}
}
}
}
}
internal interface MethodSink {
fun onMalwareDetected(packageInfo: List<SuspiciousAppInfo>)
}
/**
* Creates a new [MethodChannel] with the specified [BinaryMessenger] instance. Sets this class
* as the [MethodCallHandler].
* If an old [MethodChannel] already exists, it will be destroyed before creating a new one.
*
* @param messenger The binary messenger to use for creating the [MethodChannel].
* @param context The Android [Context] associated with this channel.
*/
fun createMethodChannel(messenger: BinaryMessenger, context: Context) {
methodChannel?.let {
Log.i("MethodCallHandler", "Tried to create channel without disposing old one.")
destroyMethodChannel()
}
methodChannel = MethodChannel(messenger, CHANNEL_NAME).also {
it.setMethodCallHandler(this)
}
this.context = context
this.pigeonApi = TalsecPigeonApi(messenger)
TalsecThreatHandler.attachMethodSink(sink)
}
/**
* Destroys the `MethodChannel` and clears associated variables.
*/
fun destroyMethodChannel() {
methodChannel?.setMethodCallHandler(null)
methodChannel = null
this.context = null
this.pigeonApi = null
TalsecThreatHandler.detachMethodSink()
}
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
when (event) {
Lifecycle.Event.ON_DESTROY -> {
context?.let {
backgroundHandlerThread.quitSafely()
}
}
else -> {
// Nothing to do
}
}
}
/**
* Handles method calls received through the [MethodChannel].
*
* @param call The method call.
* @param result The result handler of the method call.
*/
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when (call.method) {
"start" -> start(call, result)
"addToWhitelist" -> addToWhitelist(call, result)
"getAppIcon" -> getAppIcon(call, result)
"blockScreenCapture" -> blockScreenCapture(call, result)
"isScreenCaptureBlocked" -> isScreenCaptureBlocked(result)
else -> result.notImplemented()
}
}
/**
* Starts freeRASP
*
* @param call The method call containing the configuration.
* @param result The result handler of the method call.
*/
private fun start(call: MethodCall, result: MethodChannel.Result) {
runResultCatching(result) {
val config = call.argument<String>("config")
val talsecConfig = Utils.toTalsecConfigThrowing(config)
context?.let {
TalsecThreatHandler.start(it, talsecConfig)
screenProtector?.enable()
} ?: throw IllegalStateException("Unable to run Talsec - context is null")
result.success(null)
}
}
private fun addToWhitelist(call: MethodCall, result: MethodChannel.Result) {
runResultCatching(result) {
val packageName = call.argument<String>("packageName")
context?.let {
if (packageName != null) {
Talsec.addToWhitelist(it, packageName)
}
} ?: throw IllegalStateException("Unable to add package to whitelist - context is null")
result.success(null)
}
}
/**
* Retrieves app icon for the given package name.
*
* @param call The method call containing the package name.
* @param result The result handler of the method call.
*/
private fun getAppIcon(call: MethodCall, result: MethodChannel.Result) {
runResultCatching(result) {
val packageName = call.argument<String>("packageName")
?: throw NullPointerException("Package name cannot be null.")
backgroundHandler.post {
context?.let {
val appIcon = Utils.parseIconBase64(it, packageName)
mainHandler.post { result.success(appIcon) }
}
}
}
}
/**
* Blocks or unblocks screen capture. Sets the window flag to secure the screen.
*
* @param call The method call containing the enable flag.
* @param result The result handler of the method call.
*/
private fun blockScreenCapture(call: MethodCall, result: MethodChannel.Result) {
runResultCatching(result) {
val enable = call.argument<Boolean>("enable") ?: false
Talsec.blockScreenCapture(activity, enable)
result.success(null)
}
}
/**
* Checks if screen capture is blocked.
*
* @param result The result handler of the method call.
*/
private fun isScreenCaptureBlocked(result: MethodChannel.Result) {
runResultCatching(result) {
result.success(Talsec.isScreenCaptureBlocked())
}
}
}