-
Notifications
You must be signed in to change notification settings - Fork 18
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
freeRASP 6.8.0 #137
base: master
Are you sure you want to change the base?
freeRASP 6.8.0 #137
Changes from all commits
df9e2a3
1ace1b8
8982a58
5400029
7c35e19
d65da87
8ef80c6
25cfcc9
af634b2
fdb5c65
5396bf1
fc03c02
fada932
3158e81
44a66b4
566599c
7831d57
2ea6dda
587dbb6
d7d190c
4e592f2
49b8262
b34c534
48ffe9e
9fb2a5f
14f6550
0eaaec0
78e4542
fade1fb
e4cbbf7
ae85a3e
466462a
477aa3b
d9cbb3c
49cb0c4
4f8f205
6443d84
50afd82
9bfa6df
b07331b
4137e8b
a4e96f6
766d42a
7e1d780
f44814d
98da53a
445ce0c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,5 @@ | ||
include: package:very_good_analysis/analysis_options.3.1.0.yaml | ||
|
||
analyzer: | ||
exclude: | ||
- '**/*.g.dart' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,12 @@ | ||
package com.aheaditec.freerasp | ||
|
||
import android.content.Context | ||
import android.content.pm.PackageInfo | ||
import android.os.Build | ||
import com.aheaditec.talsec_security.security.api.SuspiciousAppInfo | ||
import io.flutter.plugin.common.MethodChannel | ||
import com.aheaditec.freerasp.generated.PackageInfo as FlutterPackageInfo | ||
import com.aheaditec.freerasp.generated.SuspiciousAppInfo as FlutterSuspiciousAppInfo | ||
|
||
/** | ||
* Executes the provided block of code and catches any exceptions thrown by it, returning the | ||
|
@@ -17,3 +23,67 @@ internal inline fun runResultCatching(result: MethodChannel.Result, block: () -> | |
result.error(err::class.java.name, err.message, null) | ||
} | ||
} | ||
|
||
/** | ||
* Converts a [SuspiciousAppInfo] instance to a [com.aheaditec.freerasp.generated.SuspiciousAppInfo] | ||
* instance used by Pigeon package for Flutter. | ||
* | ||
* @return A new [com.aheaditec.freerasp.generated.SuspiciousAppInfo] object with information from | ||
* this [SuspiciousAppInfo]. | ||
*/ | ||
internal fun SuspiciousAppInfo.toPigeon(context: Context): FlutterSuspiciousAppInfo { | ||
return FlutterSuspiciousAppInfo(this.packageInfo.toPigeon(context), this.reason) | ||
} | ||
|
||
/** | ||
* Converts a [PackageInfo] instance to a [com.aheaditec.freerasp.generated.PackageInfo] instance | ||
* used by Pigeon package for Flutter. | ||
* | ||
* @return A new [com.aheaditec.freerasp.generated.PackageInfo] object with information from | ||
* this [PackageInfo]. | ||
*/ | ||
private fun PackageInfo.toPigeon(context: Context): FlutterPackageInfo { | ||
return FlutterPackageInfo( | ||
packageName = packageName, | ||
appName = applicationInfo?.name, | ||
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. applicationInfo?.name returns just package name-style string, to get the app name, we have to use something like this: https://github.com/talsec/Free-RASP-ReactNative/blob/release-3.10.0/android/src/main/java/com/freeraspreactnative/utils/Utils.kt#L26 |
||
version = getVersionString(), | ||
appIcon = Utils.parseIconBase64(context, packageName), | ||
installationSource = Utils.getInstallerPackageName(context, packageName), | ||
) | ||
} | ||
|
||
/** | ||
* Retrieves the version string of the package. | ||
* | ||
* For devices running on Android P (API 28) and above, this method returns the `longVersionCode`. | ||
* For older versions, it returns the `versionCode` (deprecated). | ||
* | ||
* @return A string representation of the version code. | ||
*/ | ||
internal fun PackageInfo.getVersionString(): String { | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { | ||
return longVersionCode.toString() | ||
} | ||
@Suppress("DEPRECATION") | ||
return versionCode.toString() | ||
} | ||
|
||
/** | ||
* Returns the encapsulated value if this instance represents success or throws the encapsulated exception | ||
* if it is a failure, executing the given action before throwing. | ||
* | ||
* This function is similar to `Result.getOrThrow()`, but with the added functionality of performing | ||
* an action before throwing the exception. | ||
* | ||
* @param action The action to be executed if the result is a failure. This action should not throw an exception. | ||
* @return The encapsulated value if the result is a success. | ||
* @throws Throwable The encapsulated exception if the result is a failure. | ||
* | ||
* @see Result.getOrThrow | ||
*/ | ||
inline fun <T> Result<T>.getOrElseThenThrow(action: () -> Unit): T { | ||
return getOrElse { | ||
action() | ||
throw it | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
package com.aheaditec.freerasp | ||
|
||
import android.content.Context | ||
import android.graphics.Bitmap | ||
import android.graphics.Canvas | ||
import android.graphics.drawable.BitmapDrawable | ||
import android.graphics.drawable.Drawable | ||
import android.os.Build | ||
import android.util.Base64 | ||
import com.aheaditec.talsec_security.security.api.TalsecConfig | ||
import org.json.JSONException | ||
import org.json.JSONObject | ||
import java.io.ByteArrayOutputStream | ||
|
||
internal object Utils { | ||
fun toTalsecConfigThrowing(configJson: String?): TalsecConfig { | ||
if (configJson == null) { | ||
throw JSONException("Configuration is null") | ||
} | ||
val json = JSONObject(configJson) | ||
|
||
val watcherMail = json.getString("watcherMail") | ||
var isProd = true | ||
if (json.has("isProd")) { | ||
isProd = json.getBoolean("isProd") | ||
} | ||
val androidConfig = json.getJSONObject("androidConfig") | ||
|
||
val packageName = androidConfig.getString("packageName") | ||
val certificateHashes = androidConfig.extractArray<String>("signingCertHashes") | ||
val alternativeStores = androidConfig.extractArray<String>("supportedStores") | ||
val blocklistedPackageNames = | ||
androidConfig.extractArray<String>("blocklistedPackageNames") | ||
val blocklistedHashes = androidConfig.extractArray<String>("blocklistedHashes") | ||
val whitelistedInstallationSources = | ||
androidConfig.extractArray<String>("whitelistedInstallationSources") | ||
|
||
val blocklistedPermissions = mutableListOf<Array<String>>() | ||
if (androidConfig.has("blocklistedPermissions")) { | ||
val permissions = androidConfig.getJSONArray("blocklistedPermissions") | ||
for (i in 0 until permissions.length()) { | ||
val permission = permissions.getJSONArray(i) | ||
val permissionList = mutableListOf<String>() | ||
for (j in 0 until permission.length()) { | ||
permissionList.add(permission.getString(j)) | ||
} | ||
Comment on lines
+38
to
+46
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. Can you make it an extension method? |
||
blocklistedPermissions.add(permissionList.toTypedArray()) | ||
} | ||
} | ||
|
||
return TalsecConfig.Builder(packageName, certificateHashes) | ||
.watcherMail(watcherMail) | ||
.supportedAlternativeStores(alternativeStores) | ||
.prod(isProd) | ||
.blocklistedPackageNames(blocklistedPackageNames) | ||
.blocklistedHashes(blocklistedHashes) | ||
.blocklistedPermissions(blocklistedPermissions.toTypedArray()) | ||
.whitelistedInstallationSources(whitelistedInstallationSources) | ||
.build() | ||
} | ||
|
||
/** | ||
* Retrieves the package name of the installer for a given app package. | ||
* | ||
* @param context The context of the application. | ||
* @param packageName The package name of the app whose installer package name is to be retrieved. | ||
* @return The package name of the installer if available, or `null` if not. | ||
*/ | ||
fun getInstallerPackageName(context: Context, packageName: String): String? { | ||
runCatching { | ||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) | ||
return context.packageManager.getInstallSourceInfo(packageName).installingPackageName | ||
@Suppress("DEPRECATION") | ||
return context.packageManager.getInstallerPackageName(packageName) | ||
} | ||
return null | ||
} | ||
|
||
/** | ||
* Converts the application icon of the specified package into a Base64 encoded string. | ||
* | ||
* @param context The context of the application. | ||
* @param packageName The package name of the app whose icon is to be converted. | ||
* @return A Base64 encoded string representing the app icon. | ||
*/ | ||
fun parseIconBase64(context: Context, packageName: String): String? { | ||
val result = runCatching { | ||
val drawable = context.packageManager.getApplicationIcon(packageName) | ||
val bitmap = drawable.toBitmap() | ||
bitmap.toBase64() | ||
} | ||
|
||
return result.getOrNull() | ||
} | ||
|
||
/** | ||
* Creates a Bitmap from a Drawable object. | ||
* | ||
* @param drawable The Drawable to be converted. | ||
* @return A Bitmap representing the drawable. | ||
*/ | ||
private fun createBitmapFromDrawable(drawable: Drawable): Bitmap { | ||
val width = if (drawable.intrinsicWidth > 0) drawable.intrinsicWidth else 1 | ||
val height = if (drawable.intrinsicHeight > 0) drawable.intrinsicHeight else 1 | ||
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) | ||
val canvas = Canvas(bitmap) | ||
|
||
drawable.setBounds(0, 0, canvas.width, canvas.height) | ||
drawable.draw(canvas) | ||
|
||
return bitmap | ||
} | ||
|
||
/** | ||
* Converts a Drawable into a Bitmap. | ||
* | ||
* @receiver The Drawable to be converted. | ||
* @return A Bitmap representing the drawable. | ||
*/ | ||
private fun Drawable.toBitmap(): Bitmap { | ||
return when (this) { | ||
is BitmapDrawable -> bitmap | ||
else -> createBitmapFromDrawable(this) | ||
} | ||
} | ||
|
||
/** | ||
* Converts a Bitmap into a Base64 encoded string. | ||
* | ||
* @receiver The Bitmap to be converted. | ||
* @return A Base64 encoded string representing the bitmap. | ||
*/ | ||
private fun Bitmap.toBase64(): String { | ||
val byteArrayOutputStream = ByteArrayOutputStream() | ||
compress(Bitmap.CompressFormat.PNG, 10, byteArrayOutputStream) | ||
val byteArray = byteArrayOutputStream.toByteArray() | ||
return Base64.encodeToString(byteArray, Base64.DEFAULT) | ||
} | ||
} | ||
|
||
inline fun <reified T> JSONObject.extractArray(key: String): Array<T> { | ||
val list = mutableListOf<T>() | ||
if (this.has(key)) { | ||
val jsonArray = this.getJSONArray(key) | ||
for (i in 0 until jsonArray.length()) { | ||
val element = when (T::class) { | ||
String::class -> jsonArray.getString(i) as T | ||
Int::class -> jsonArray.getInt(i) as T | ||
Double::class -> jsonArray.getDouble(i) as T | ||
Boolean::class -> jsonArray.getBoolean(i) as T | ||
Long::class -> jsonArray.getLong(i) as T | ||
else -> throw IllegalArgumentException("Unsupported type") | ||
} | ||
list.add(element) | ||
} | ||
} | ||
return list.toTypedArray() | ||
} |
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.
Can you announce it as a new feature?