diff --git a/CHANGELOG.md b/CHANGELOG.md
index 86900ac..6317d72 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,43 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [9.0.0] - 2026-05-15
+
+- Android SDK version: 18.3.0
+- iOS SDK version: 6.14.4
+
+### Breaking
+
+- `SuspiciousAppInfo.reason` (String) renamed to `reasons` (string[])
+- Value `"blacklist"` in `reasons` renamed to `"blocklist"`
+- Removed `TalsecMalwareConfig` type and `TalsecAndroidConfig.malwareConfig` field
+- `SuspiciousAppDetectionConfig.malwareScanScope` and `reasonMode` are now required
+
+### Cordova
+
+#### Removed
+
+- `TalsecMalwareConfig` type and `TalsecAndroidConfig.malwareConfig` field
+
+### Android
+
+#### Added
+
+- New API class `SuspiciousAppDetectionConfig` that can be used to configure malware detection
+- New API for malware detection configuration in `TalsecConfig`, see `TalsecConfig.Builder#suspiciousAppDetection`
+
+#### Fixed
+
+- Fixed `VerifyError` caused by `JaCoCo` bytecode instrumentation
+- Fixed a potential cause of crash in the multi-instance detector
+- Fixed Java interoperability of `ScreenProtector` methods
+- Fixed Kotlin classpath conflicts in SDK dependency resolution (Kotlin 2.0.0)
+
+#### Changed
+
+- Fine-tuned location spoofing detection
+- Modified malware incident log structure for better aggregation
+
## [8.3.1] - 2026-03-24
- Android SDK version: 18.0.4
diff --git a/example/package-lock.json b/example/package-lock.json
index 5479cb1..ca42868 100644
--- a/example/package-lock.json
+++ b/example/package-lock.json
@@ -39,8 +39,8 @@
"@types/jasmine": "~5.1.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
- "cordova-android": "^14.0.1",
- "cordova-ios": "^8.0.0",
+ "cordova-android": "^15.0.0",
+ "cordova-ios": "^8.0.1",
"cordova-plugin-device": "2.0.2",
"cordova-plugin-ionic-keyboard": "^2.0.5",
"cordova-plugin-splashscreen": "5.0.2",
@@ -62,7 +62,7 @@
},
"..": {
"name": "cordova-talsec-plugin-freerasp",
- "version": "8.3.0",
+ "version": "9.0.0",
"dev": true,
"license": "MIT",
"devDependencies": {
@@ -5177,13 +5177,13 @@
}
},
"node_modules/@xmldom/xmldom": {
- "version": "0.8.11",
- "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz",
- "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==",
+ "version": "0.9.10",
+ "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.10.tgz",
+ "integrity": "sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==",
"dev": true,
"license": "MIT",
"engines": {
- "node": ">=10.0.0"
+ "node": ">=14.6"
}
},
"node_modules/@xtuc/ieee754": {
@@ -6623,37 +6623,37 @@
}
},
"node_modules/cordova-android": {
- "version": "14.0.1",
- "resolved": "https://registry.npmjs.org/cordova-android/-/cordova-android-14.0.1.tgz",
- "integrity": "sha512-HMBMdGu/JlSQtmBuDEpKWf/pE75SpF3FksxZ+mqYuL3qSIN8lN/QsNurwYaPAP7zWXN2DNpvwlpOJItS5VhdLg==",
+ "version": "15.0.0",
+ "resolved": "https://registry.npmjs.org/cordova-android/-/cordova-android-15.0.0.tgz",
+ "integrity": "sha512-EpFSKUtBLJ7bTpuVD7NeC6toAooi5PI6VIR2jd8Ut5PJu7HSR5tPRwS87Q1DS03RSyDTlroB64JPUWC0pmAhnw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "android-versions": "^2.1.0",
- "cordova-common": "^5.0.1",
- "dedent": "^1.5.3",
+ "android-versions": "^2.1.1",
+ "cordova-common": "^6.0.0",
+ "dedent": "^1.7.1",
"execa": "^5.1.1",
"fast-glob": "^3.3.3",
"is-path-inside": "^3.0.3",
- "nopt": "^8.1.0",
+ "nopt": "^9.0.0",
"properties-parser": "^0.6.0",
- "semver": "^7.7.1",
- "string-argv": "^0.3.1",
+ "semver": "^7.7.4",
+ "string-argv": "^0.3.2",
"untildify": "^4.0.0",
- "which": "^5.0.0"
+ "which": "^6.0.1"
},
"engines": {
- "node": ">=20.5.0"
+ "node": ">=20.17.0 || >=22.9.0"
}
},
"node_modules/cordova-android/node_modules/abbrev": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz",
- "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-4.0.0.tgz",
+ "integrity": "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==",
"dev": true,
"license": "ISC",
"engines": {
- "node": "^18.17.0 || >=20.5.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/cordova-android/node_modules/fast-glob": {
@@ -6674,35 +6674,35 @@
}
},
"node_modules/cordova-android/node_modules/isexe": {
- "version": "3.1.5",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz",
- "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz",
+ "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==",
"dev": true,
"license": "BlueOak-1.0.0",
"engines": {
- "node": ">=18"
+ "node": ">=20"
}
},
"node_modules/cordova-android/node_modules/nopt": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz",
- "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==",
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-9.0.0.tgz",
+ "integrity": "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==",
"dev": true,
"license": "ISC",
"dependencies": {
- "abbrev": "^3.0.0"
+ "abbrev": "^4.0.0"
},
"bin": {
"nopt": "bin/nopt.js"
},
"engines": {
- "node": "^18.17.0 || >=20.5.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/cordova-android/node_modules/semver": {
- "version": "7.7.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
- "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz",
+ "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==",
"dev": true,
"license": "ISC",
"bin": {
@@ -6713,43 +6713,38 @@
}
},
"node_modules/cordova-android/node_modules/which": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz",
- "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz",
+ "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==",
"dev": true,
"license": "ISC",
"dependencies": {
- "isexe": "^3.1.1"
+ "isexe": "^4.0.0"
},
"bin": {
"node-which": "bin/which.js"
},
"engines": {
- "node": "^18.17.0 || >=20.5.0"
+ "node": "^20.17.0 || >=22.9.0"
}
},
"node_modules/cordova-common": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/cordova-common/-/cordova-common-5.0.1.tgz",
- "integrity": "sha512-OA2NQ6wvhNz4GytPYwTdlA9xfG7Yf7ufkj4u97m3rUfoL/AECwwj0GVT2CYpk/0Fk6HyuHA3QYCxfDPYsKzI1A==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cordova-common/-/cordova-common-6.0.0.tgz",
+ "integrity": "sha512-16WPC1DuxVdshV3RoQUXqhcJVdhxWGwiFysA4TkYuboqoev6mgt0JuIJFxmQbzR/DuyuONaVe0L0O0Hf1C08Mg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@netflix/nerror": "^1.1.3",
"ansi": "^0.3.1",
"bplist-parser": "^0.3.2",
- "cross-spawn": "^7.0.6",
"elementtree": "^0.1.7",
"endent": "^2.1.0",
"fast-glob": "^3.3.3",
- "lodash.zip": "^4.2.0",
- "plist": "^3.1.0",
- "q": "^1.5.1",
- "read-chunk": "^3.2.0",
- "strip-bom": "^4.0.0"
+ "plist": "^3.1.0"
},
"engines": {
- "node": ">=16.0.0"
+ "node": ">=20.9.0"
}
},
"node_modules/cordova-common/node_modules/fast-glob": {
@@ -6769,20 +6764,10 @@
"node": ">=8.6.0"
}
},
- "node_modules/cordova-common/node_modules/strip-bom": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
- "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/cordova-ios": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/cordova-ios/-/cordova-ios-8.0.0.tgz",
- "integrity": "sha512-QsynOV8rnRIhDC3qwM1KdRr1gy5RaqzVCzdOaB+DSBPeR5wVEUGpyyJO0FzlCACzY5X25iDc5O3kbn/F06dJ5Q==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cordova-ios/-/cordova-ios-8.0.1.tgz",
+ "integrity": "sha512-jktJmh0XMHdkKZuQXgh1Dv6WtfB3BXBH27U2LX0+cvcELgymIy59eJ5ckPuqu/kNAroUqRc9Tf+zUqG3HGvcmQ==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -6811,42 +6796,6 @@
"node": "^20.17.0 || >=22.9.0"
}
},
- "node_modules/cordova-ios/node_modules/cordova-common": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/cordova-common/-/cordova-common-6.0.0.tgz",
- "integrity": "sha512-16WPC1DuxVdshV3RoQUXqhcJVdhxWGwiFysA4TkYuboqoev6mgt0JuIJFxmQbzR/DuyuONaVe0L0O0Hf1C08Mg==",
- "dev": true,
- "license": "Apache-2.0",
- "dependencies": {
- "@netflix/nerror": "^1.1.3",
- "ansi": "^0.3.1",
- "bplist-parser": "^0.3.2",
- "elementtree": "^0.1.7",
- "endent": "^2.1.0",
- "fast-glob": "^3.3.3",
- "plist": "^3.1.0"
- },
- "engines": {
- "node": ">=20.9.0"
- }
- },
- "node_modules/cordova-ios/node_modules/fast-glob": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
- "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@nodelib/fs.stat": "^2.0.2",
- "@nodelib/fs.walk": "^1.2.3",
- "glob-parent": "^5.1.2",
- "merge2": "^1.3.0",
- "micromatch": "^4.0.8"
- },
- "engines": {
- "node": ">=8.6.0"
- }
- },
"node_modules/cordova-ios/node_modules/isexe": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz",
@@ -6874,9 +6823,9 @@
}
},
"node_modules/cordova-ios/node_modules/semver": {
- "version": "7.7.4",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
- "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz",
+ "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==",
"dev": true,
"license": "ISC",
"bin": {
@@ -7274,9 +7223,9 @@
}
},
"node_modules/dedent": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.1.tgz",
- "integrity": "sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg==",
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz",
+ "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==",
"dev": true,
"license": "MIT",
"peerDependencies": {
@@ -11007,13 +10956,6 @@
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true
},
- "node_modules/lodash.zip": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz",
- "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/log-symbols": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
@@ -12380,16 +12322,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/p-finally": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
- "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -12459,16 +12391,6 @@
"node": ">= 4"
}
},
- "node_modules/p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/package-json-from-dist": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
@@ -12710,7 +12632,7 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
- "devOptional": true,
+ "optional": true,
"engines": {
"node": ">=6"
}
@@ -12814,13 +12736,13 @@
}
},
"node_modules/plist": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz",
- "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==",
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.1.tgz",
+ "integrity": "sha512-ZIfcLJC+7E7FBFnDxm9MPmt7D+DidyQ26lewieO75AdhA2ayMtsJSES0iWzqJQbcVRSrTufQoy0DR94xHue0oA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@xmldom/xmldom": "^0.8.8",
+ "@xmldom/xmldom": "^0.9.10",
"base64-js": "^1.5.1",
"xmlbuilder": "^15.1.1"
},
@@ -12981,9 +12903,10 @@
}
},
"node_modules/prettier": {
- "version": "3.5.1",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.1.tgz",
- "integrity": "sha512-hPpFQvHwL3Qv5AdRvBFMhnKo4tYxp0ReXiPn2bxkiohEX6mBeBwEpBSQTkD458RaaDKQMYSp4hX4UtfUTA5wDw==",
+ "version": "3.8.3",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz",
+ "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==",
+ "license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
@@ -13069,18 +12992,6 @@
"integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
"devOptional": true
},
- "node_modules/q": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
- "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==",
- "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.6.0",
- "teleport": ">=0.2.0"
- }
- },
"node_modules/qjobs": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz",
@@ -13153,20 +13064,6 @@
"node": ">= 0.8"
}
},
- "node_modules/read-chunk": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-3.2.0.tgz",
- "integrity": "sha512-CEjy9LCzhmD7nUpJ1oVOE6s/hBkejlcJEgLQHVnQznOSilOPb+kpKktlLfFDK3/WP43+F80xkUTM2VOkYoSYvQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "pify": "^4.0.1",
- "with-open-file": "^0.1.6"
- },
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
@@ -14834,9 +14731,10 @@
}
},
"node_modules/tslib": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
- "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA=="
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "license": "0BSD"
},
"node_modules/tuf-js": {
"version": "2.2.1",
@@ -16158,21 +16056,6 @@
"resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz",
"integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ=="
},
- "node_modules/with-open-file": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/with-open-file/-/with-open-file-0.1.7.tgz",
- "integrity": "sha512-ecJS2/oHtESJ1t3ZfMI3B7KIDKyfN0O16miWxdn30zdh66Yd3LsRFebXZXq6GU4xfxLf6nVxp9kIqElb5fqczA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "p-finally": "^1.0.0",
- "p-try": "^2.1.0",
- "pify": "^4.0.1"
- },
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/word-wrap": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
@@ -16368,6 +16251,7 @@
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz",
"integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==",
+ "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).",
"dev": true,
"license": "MIT",
"bin": {
@@ -16475,6 +16359,27 @@
"version": "0.14.10",
"resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.10.tgz",
"integrity": "sha512-YGAhaO7J5ywOXW6InXNlLmfU194F8lVgu7bRntUF3TiG8Y3nBK0x1UJJuHUP/e8IyihkjCYqhCScpSwnlaSRkQ=="
+ },
+ "temp_plugin/package": {
+ "name": "cordova-talsec-plugin-freerasp",
+ "version": "9.0.0",
+ "extraneous": true,
+ "license": "MIT",
+ "devDependencies": {
+ "@cordova/eslint-config": "^5.0.0",
+ "@types/cordova": "^11.0.2",
+ "@types/node": "^20.8.10",
+ "@typescript-eslint/eslint-plugin": "^6.9.1",
+ "@typescript-eslint/parser": "^6.9.1",
+ "esbuild": "^0.27.2",
+ "eslint": "^8.40.0",
+ "eslint-config-prettier": "^8.10.0",
+ "eslint-plugin-import": "^2.27.5",
+ "eslint-plugin-prettier": "^4.2.1",
+ "prettier": "^3.0.3",
+ "prettier-eslint": "^16.1.2",
+ "typescript": "^5.2.2"
+ }
}
}
}
diff --git a/example/package.json b/example/package.json
index 529144b..0f7b084 100644
--- a/example/package.json
+++ b/example/package.json
@@ -41,8 +41,8 @@
"@types/jasmine": "~5.1.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
- "cordova-android": "^14.0.1",
- "cordova-ios": "^8.0.0",
+ "cordova-android": "^15.0.0",
+ "cordova-ios": "^8.0.1",
"cordova-plugin-device": "2.0.2",
"cordova-plugin-ionic-keyboard": "^2.0.5",
"cordova-plugin-splashscreen": "5.0.2",
@@ -76,4 +76,4 @@
"ios"
]
}
-}
\ No newline at end of file
+}
diff --git a/example/src/app/app.component.ts b/example/src/app/app.component.ts
index cceed04..3913a8b 100644
--- a/example/src/app/app.component.ts
+++ b/example/src/app/app.component.ts
@@ -1,7 +1,11 @@
import { Component, OnInit, NgZone } from '@angular/core';
import { commonChecks, iosChecks, androidChecks } from './utils/checks';
import { SuspiciousAppsService } from './services/suspicious-apps.service';
-import { SuspiciousAppInfo, Talsec } from 'cordova-talsec-plugin-freerasp';
+import {
+ SuspiciousAppInfo,
+ Talsec,
+ TalsecConfig,
+} from 'cordova-talsec-plugin-freerasp';
declare var cordova: any;
declare var talsec: Talsec;
@@ -25,14 +29,14 @@ export class AppComponent implements OnInit {
toastColor: 'success' | 'warning' = 'success';
checksFinished = false;
- config = {
+ config: TalsecConfig = {
androidConfig: {
packageName: 'io.ionic.starter',
certificateHashes: ['AKoRuyLMM91E7lX/Zqp3u4jMmd0A7hH/Iqozu0TMVd0='],
- malwareConfig: {
- blacklistedHashes: ['FgvSehLMM91E7lX/Zqp3u4jMmd0A7hH/Iqozu0TMVd0u'],
- blacklistedPackageNames: ['io.ionic.starter'],
- suspiciousPermissions: [
+ suspiciousAppDetectionConfig: {
+ hashes: ['FgvSehLMM91E7lX/Zqp3u4jMmd0A7hH/Iqozu0TMVd0u'],
+ packageNames: ['io.ionic.starter'],
+ requestedPermissions: [
[
'android.permission.INTERNET',
'android.permission.ACCESS_COARSE_LOCATION',
@@ -40,7 +44,11 @@ export class AppComponent implements OnInit {
['android.permission.BLUETOOTH'],
['android.permission.BATTERY_STATS'],
],
- whitelistedInstallationSources: ['com.apkpure.aegon'],
+ scanScope: {
+ scopeType: 'SIDELOADED_ONLY',
+ trustedInstallSources: ['com.apkpure.aegon'],
+ },
+ reasonMode: 'HIGHEST_CONFIDENCE',
},
},
iosConfig: {
diff --git a/example/src/app/components/malware-item/malware-item.component.html b/example/src/app/components/malware-item/malware-item.component.html
index 1f5a3dc..2ef80a6 100644
--- a/example/src/app/components/malware-item/malware-item.component.html
+++ b/example/src/app/components/malware-item/malware-item.component.html
@@ -65,8 +65,8 @@
Not specified
}
- Detection reason:
- {{ susApp.reason }}Detection reasons:
+ {{ susApp.reasons.join(', ') }}
diff --git a/example/src/app/components/malware-item/malware-item.component.ts b/example/src/app/components/malware-item/malware-item.component.ts
index 9e3e6e8..1adf632 100644
--- a/example/src/app/components/malware-item/malware-item.component.ts
+++ b/example/src/app/components/malware-item/malware-item.component.ts
@@ -1,4 +1,4 @@
-import { Component, Input, OnInit } from '@angular/core';
+import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
import { SuspiciousAppInfo, Talsec } from 'cordova-talsec-plugin-freerasp';
declare var talsec: Talsec;
@@ -11,6 +11,8 @@ export class MalwareItemComponent implements OnInit {
@Input() susApp!: SuspiciousAppInfo;
expanded = false;
+ constructor(private cdr: ChangeDetectorRef) {}
+
ngOnInit(): void {
this.loadAppIcon();
}
@@ -19,6 +21,7 @@ export class MalwareItemComponent implements OnInit {
this.susApp.packageInfo.appIcon = await talsec.getAppIcon(
this.susApp.packageInfo.packageName,
);
+ this.cdr.detectChanges();
}
toggleExpanded() {
diff --git a/package-lock.json b/package-lock.json
index 771af8e..5f0aca4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "cordova-talsec-plugin-freerasp",
- "version": "8.3.0",
+ "version": "9.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "cordova-talsec-plugin-freerasp",
- "version": "8.3.0",
+ "version": "9.0.0",
"license": "MIT",
"devDependencies": {
"@cordova/eslint-config": "^5.0.0",
diff --git a/package.json b/package.json
index 34f4ff7..97e4595 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "cordova-talsec-plugin-freerasp",
- "version": "8.3.1",
+ "version": "9.0.0",
"description": "Cordova plugin for improving app security and threat monitoring on Android and iOS mobile devices.",
"cordova": {
"id": "cordova-talsec-plugin-freerasp",
diff --git a/plugin.xml b/plugin.xml
index 2bd5a4d..a01ab2b 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -2,7 +2,7 @@
+ version="9.0.0">
freerasp
Talsec (info@talsec.app)
diff --git a/src/android/TalsecPlugin.kt b/src/android/TalsecPlugin.kt
index ed9f839..bb7ec8b 100644
--- a/src/android/TalsecPlugin.kt
+++ b/src/android/TalsecPlugin.kt
@@ -18,8 +18,8 @@ import com.aheaditec.talsec.cordova.utils.ScreenCaptureStatus
import com.aheaditec.talsec.cordova.utils.toEncodedJsonArray
import com.aheaditec.talsec.cordova.utils.getArraySafe
import com.aheaditec.talsec.cordova.utils.getBooleanSafe
-import com.aheaditec.talsec.cordova.utils.getNestedArraySafe
import com.aheaditec.talsec.cordova.utils.getStringSafe
+import com.aheaditec.talsec.cordova.utils.toSuspiciousAppDetectionConfig
import com.aheaditec.talsec_security.security.api.SuspiciousAppInfo
import com.aheaditec.talsec_security.security.api.Talsec
import com.aheaditec.talsec_security.security.api.TalsecConfig
@@ -296,12 +296,10 @@ class TalsecPlugin : CordovaPlugin() {
.prod(json.getBooleanSafe("isProd"))
.killOnBypass(json.getBooleanSafe("killOnBypass", false))
- if (androidConfig.has("malwareConfig")) {
- val malwareConfig = androidConfig.getJSONObject("malwareConfig")
- talsecBuilder.whitelistedInstallationSources(malwareConfig.getArraySafe("whitelistedInstallationSources"))
- talsecBuilder.blacklistedHashes(malwareConfig.getArraySafe("blacklistedHashes"))
- talsecBuilder.blacklistedPackageNames(malwareConfig.getArraySafe("blacklistedPackageNames"))
- talsecBuilder.suspiciousPermissions(malwareConfig.getNestedArraySafe("suspiciousPermissions"))
+ if (androidConfig.has("suspiciousAppDetectionConfig")) {
+ val suspiciousAppDetectionConfig = androidConfig.getJSONObject("suspiciousAppDetectionConfig")
+ .toSuspiciousAppDetectionConfig()
+ talsecBuilder.suspiciousAppDetection(suspiciousAppDetectionConfig)
}
return talsecBuilder.build()
}
diff --git a/src/android/models/CordovaSuspiciousAppInfo.kt b/src/android/models/CordovaSuspiciousAppInfo.kt
index 54814f8..201a916 100644
--- a/src/android/models/CordovaSuspiciousAppInfo.kt
+++ b/src/android/models/CordovaSuspiciousAppInfo.kt
@@ -9,7 +9,7 @@ import kotlinx.serialization.Serializable
@Serializable
data class CordovaSuspiciousAppInfo(
val packageInfo: CordovaPackageInfo,
- val reason: String,
+ val reasons: Set,
val permissions: Set?
)
diff --git a/src/android/talsec.gradle b/src/android/talsec.gradle
index 18ece97..a983add 100644
--- a/src/android/talsec.gradle
+++ b/src/android/talsec.gradle
@@ -9,7 +9,7 @@ repositories {
}
dependencies {
- implementation "com.aheaditec.talsec.security:TalsecSecurity-Community-Cordova:18.0.4"
+ implementation "com.aheaditec.talsec.security:TalsecSecurity-Community-Cordova:18.3.0"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1"
}
diff --git a/src/android/utils/Extensions.kt b/src/android/utils/Extensions.kt
index ee0e5d2..66d907f 100644
--- a/src/android/utils/Extensions.kt
+++ b/src/android/utils/Extensions.kt
@@ -7,6 +7,10 @@ import android.util.Log
import com.aheaditec.talsec.cordova.models.CordovaPackageInfo
import com.aheaditec.talsec.cordova.models.CordovaSuspiciousAppInfo
import com.aheaditec.talsec_security.security.api.SuspiciousAppInfo
+import com.aheaditec.talsec_security.security.api.SuspiciousAppDetectionConfig
+import com.aheaditec.talsec_security.security.api.MalwareScanScope
+import com.aheaditec.talsec_security.security.api.ScopeType
+import com.aheaditec.talsec_security.security.api.ReasonMode
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.json.JSONArray
@@ -69,7 +73,7 @@ internal fun JSONObject.getStringSafe(key: String): String? {
internal fun SuspiciousAppInfo.toCordovaSuspiciousAppInfo(context: Context): CordovaSuspiciousAppInfo {
return CordovaSuspiciousAppInfo(
packageInfo = this.packageInfo.toCordovaPackageInfo(context),
- reason = this.reason,
+ reasons = this.reasons,
permissions = this.permissions
)
}
@@ -87,6 +91,32 @@ internal fun PackageInfo.toCordovaPackageInfo(context: Context): CordovaPackageI
)
}
+internal fun JSONObject.toScanScope(): MalwareScanScope {
+ val scopeType = ScopeType.valueOf(getString("scopeType"))
+ val trustedInstallSources = optJSONArray("trustedInstallSources")
+ ?.toPrimitiveArray()?.toList()
+ return MalwareScanScope(scopeType, trustedInstallSources)
+}
+
+internal fun JSONObject.toSuspiciousAppDetectionConfig(): SuspiciousAppDetectionConfig {
+ val packageNames = this.getArraySafe("packageNames").toSet().ifEmpty { null }
+ val hashes = this.getArraySafe("hashes").toSet().ifEmpty { null }
+ val requestedPermissions = this.getNestedArraySafe("requestedPermissions")
+ .map { it.toSet() }.toSet().ifEmpty { null }
+ val grantedPermissions = this.getNestedArraySafe("grantedPermissions")
+ .map { it.toSet() }.toSet().ifEmpty { null }
+ val scanScope = getJSONObject("scanScope").toScanScope()
+ val reasonMode = ReasonMode.valueOf(getString("reasonMode"))
+ return SuspiciousAppDetectionConfig(
+ packageNames,
+ hashes,
+ requestedPermissions,
+ grantedPermissions,
+ scanScope,
+ reasonMode
+ )
+}
+
/**
* Convert the Talsec's SuspiciousAppInfo to base64-encoded json array,
* which can be then sent to Cordova
diff --git a/www/dist/talsec.js b/www/dist/talsec.js
index cc98824..dde16b8 100644
--- a/www/dist/talsec.js
+++ b/www/dist/talsec.js
@@ -247,7 +247,7 @@ var toSuspiciousAppInfo = (base64Value) => {
const packageInfo = data.packageInfo;
return {
packageInfo,
- reason: data.reason,
+ reasons: data.reasons,
permissions: data.permissions
};
};
@@ -405,6 +405,33 @@ var registerRaspExecutionStateListener = async (config) => {
);
};
+// www/src/utils/config.ts
+var DEFAULT_SCAN_SCOPE = {
+ scopeType: "SIDELOADED_ONLY"
+};
+var DEFAULT_REASON_MODE = "HIGHEST_CONFIDENCE";
+var withDetectionDefaults = (config) => ({
+ ...config,
+ scanScope: config.scanScope ?? DEFAULT_SCAN_SCOPE,
+ reasonMode: config.reasonMode ?? DEFAULT_REASON_MODE
+});
+var normalizeAndroidConfig = (androidConfig) => {
+ if (!androidConfig.suspiciousAppDetectionConfig) return androidConfig;
+ return {
+ ...androidConfig,
+ suspiciousAppDetectionConfig: withDetectionDefaults(
+ androidConfig.suspiciousAppDetectionConfig
+ )
+ };
+};
+var withDefaults = (config) => {
+ if (!config.androidConfig) return config;
+ return {
+ ...config,
+ androidConfig: normalizeAndroidConfig(config.androidConfig)
+ };
+};
+
// www/src/api/methods/cordova.ts
var start = async (config, eventListenerConfig, raspExecutionStateActions) => {
await registerThreatListener(eventListenerConfig);
@@ -426,7 +453,7 @@ var start = async (config, eventListenerConfig, raspExecutionStateActions) => {
},
"TalsecPlugin",
"start",
- [config]
+ [withDefaults(config)]
);
});
};
diff --git a/www/dist/types/types/types.d.ts b/www/dist/types/types/types.d.ts
index bb54bd2..5f601c5 100644
--- a/www/dist/types/types/types.d.ts
+++ b/www/dist/types/types/types.d.ts
@@ -9,21 +9,29 @@ export type TalsecAndroidConfig = {
packageName: string;
certificateHashes: string[];
supportedAlternativeStores?: string[];
- malwareConfig?: TalsecMalwareConfig;
+ suspiciousAppDetectionConfig?: SuspiciousAppDetectionConfig;
+};
+export type ScopeType = 'SIDELOADED_ONLY' | 'SIDELOADED_AND_SYSTEM_EXCLUDE_OEM' | 'SIDELOADED_AND_OEM' | 'SIDELOADED_AND_SYSTEM_AND_OEM' | 'ALL';
+export type ReasonMode = 'ALL' | 'HIGHEST_CONFIDENCE';
+export type ScanScope = {
+ scopeType: ScopeType;
+ trustedInstallSources?: string[];
+};
+export type SuspiciousAppDetectionConfig = {
+ packageNames?: string[];
+ hashes?: string[];
+ requestedPermissions?: string[][];
+ grantedPermissions?: string[][];
+ scanScope: ScanScope;
+ reasonMode: ReasonMode;
};
export type TalsecIosConfig = {
appBundleIds: string;
appTeamId: string;
};
-export type TalsecMalwareConfig = {
- blacklistedHashes?: string[];
- blacklistedPackageNames?: string[];
- suspiciousPermissions?: string[][];
- whitelistedInstallationSources?: string[];
-};
export type SuspiciousAppInfo = {
packageInfo: PackageInfo;
- reason: string;
+ reasons: string[];
permissions?: string[];
};
export type PackageInfo = {
diff --git a/www/dist/types/utils/config.d.ts b/www/dist/types/utils/config.d.ts
new file mode 100644
index 0000000..683e00a
--- /dev/null
+++ b/www/dist/types/utils/config.d.ts
@@ -0,0 +1,2 @@
+import { TalsecConfig } from '../types/types';
+export declare const withDefaults: (config: TalsecConfig) => TalsecConfig;
diff --git a/www/src/api/methods/cordova.ts b/www/src/api/methods/cordova.ts
index 869c115..8ee1a5d 100644
--- a/www/src/api/methods/cordova.ts
+++ b/www/src/api/methods/cordova.ts
@@ -6,6 +6,7 @@ import {
import { registerThreatListener } from '../listeners/threat';
import { registerRaspExecutionStateListener } from '../listeners/raspExecutionState';
import { onInvalidCallback } from './native';
+import { withDefaults } from '../../utils/config';
export const start = async (
config: TalsecConfig,
@@ -32,7 +33,7 @@ export const start = async (
},
'TalsecPlugin',
'start',
- [config],
+ [withDefaults(config)],
);
});
};
diff --git a/www/src/types/types.ts b/www/src/types/types.ts
index 0d8433e..167bfab 100644
--- a/www/src/types/types.ts
+++ b/www/src/types/types.ts
@@ -10,7 +10,30 @@ export type TalsecAndroidConfig = {
packageName: string;
certificateHashes: string[];
supportedAlternativeStores?: string[];
- malwareConfig?: TalsecMalwareConfig;
+ suspiciousAppDetectionConfig?: SuspiciousAppDetectionConfig;
+};
+
+export type ScopeType =
+ | 'SIDELOADED_ONLY'
+ | 'SIDELOADED_AND_SYSTEM_EXCLUDE_OEM'
+ | 'SIDELOADED_AND_OEM'
+ | 'SIDELOADED_AND_SYSTEM_AND_OEM'
+ | 'ALL';
+
+export type ReasonMode = 'ALL' | 'HIGHEST_CONFIDENCE';
+
+export type ScanScope = {
+ scopeType: ScopeType;
+ trustedInstallSources?: string[];
+};
+
+export type SuspiciousAppDetectionConfig = {
+ packageNames?: string[];
+ hashes?: string[];
+ requestedPermissions?: string[][];
+ grantedPermissions?: string[][];
+ scanScope: ScanScope;
+ reasonMode: ReasonMode;
};
export type TalsecIosConfig = {
@@ -18,16 +41,9 @@ export type TalsecIosConfig = {
appTeamId: string;
};
-export type TalsecMalwareConfig = {
- blacklistedHashes?: string[];
- blacklistedPackageNames?: string[];
- suspiciousPermissions?: string[][];
- whitelistedInstallationSources?: string[];
-};
-
export type SuspiciousAppInfo = {
packageInfo: PackageInfo;
- reason: string;
+ reasons: string[];
permissions?: string[];
};
diff --git a/www/src/utils/config.ts b/www/src/utils/config.ts
new file mode 100644
index 0000000..dcb024c
--- /dev/null
+++ b/www/src/utils/config.ts
@@ -0,0 +1,40 @@
+import {
+ ReasonMode,
+ ScanScope,
+ SuspiciousAppDetectionConfig,
+ TalsecAndroidConfig,
+ TalsecConfig,
+} from '../types/types';
+
+const DEFAULT_SCAN_SCOPE: ScanScope = {
+ scopeType: 'SIDELOADED_ONLY',
+};
+const DEFAULT_REASON_MODE: ReasonMode = 'HIGHEST_CONFIDENCE';
+
+const withDetectionDefaults = (
+ config: SuspiciousAppDetectionConfig,
+): SuspiciousAppDetectionConfig => ({
+ ...config,
+ scanScope: config.scanScope ?? DEFAULT_SCAN_SCOPE,
+ reasonMode: config.reasonMode ?? DEFAULT_REASON_MODE,
+});
+
+const normalizeAndroidConfig = (
+ androidConfig: TalsecAndroidConfig,
+): TalsecAndroidConfig => {
+ if (!androidConfig.suspiciousAppDetectionConfig) return androidConfig;
+ return {
+ ...androidConfig,
+ suspiciousAppDetectionConfig: withDetectionDefaults(
+ androidConfig.suspiciousAppDetectionConfig,
+ ),
+ };
+};
+
+export const withDefaults = (config: TalsecConfig): TalsecConfig => {
+ if (!config.androidConfig) return config;
+ return {
+ ...config,
+ androidConfig: normalizeAndroidConfig(config.androidConfig),
+ };
+};
diff --git a/www/src/utils/malware.ts b/www/src/utils/malware.ts
index 841b611..6a62ab1 100644
--- a/www/src/utils/malware.ts
+++ b/www/src/utils/malware.ts
@@ -18,7 +18,7 @@ const toSuspiciousAppInfo = (base64Value: string): SuspiciousAppInfo => {
const packageInfo = data.packageInfo as PackageInfo;
return {
packageInfo,
- reason: data.reason,
+ reasons: data.reasons,
permissions: data.permissions,
} as SuspiciousAppInfo;
};