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; };