@cap-kit/integrity 8.0.0-next.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CapKitIntegrity.podspec +17 -0
- package/LICENSE +21 -0
- package/Package.swift +26 -0
- package/README.md +1104 -0
- package/android/build.gradle +104 -0
- package/android/src/main/AndroidManifest.xml +21 -0
- package/android/src/main/java/io/capkit/integrity/IntegrityCheckOptions.kt +37 -0
- package/android/src/main/java/io/capkit/integrity/IntegrityConfig.kt +59 -0
- package/android/src/main/java/io/capkit/integrity/IntegrityError.kt +40 -0
- package/android/src/main/java/io/capkit/integrity/IntegrityImpl.kt +319 -0
- package/android/src/main/java/io/capkit/integrity/IntegrityPlugin.kt +475 -0
- package/android/src/main/java/io/capkit/integrity/IntegrityReportBuilder.kt +130 -0
- package/android/src/main/java/io/capkit/integrity/IntegritySignalBuilder.kt +72 -0
- package/android/src/main/java/io/capkit/integrity/emulator/IntegrityEmulatorChecks.kt +38 -0
- package/android/src/main/java/io/capkit/integrity/filesystem/IntegrityFilesystemChecks.kt +51 -0
- package/android/src/main/java/io/capkit/integrity/hook/IntegrityHookChecks.kt +61 -0
- package/android/src/main/java/io/capkit/integrity/remote/IntegrityRemoteAttestor.kt +49 -0
- package/android/src/main/java/io/capkit/integrity/root/IntegrityRootDetector.kt +136 -0
- package/android/src/main/java/io/capkit/integrity/runtime/IntegrityRuntimeChecks.kt +87 -0
- package/android/src/main/java/io/capkit/integrity/ui/IntegrityBlockActivity.kt +173 -0
- package/android/src/main/java/io/capkit/integrity/ui/IntegrityUISignals.kt +57 -0
- package/android/src/main/java/io/capkit/integrity/utils/IntegrityLogger.kt +85 -0
- package/android/src/main/java/io/capkit/integrity/utils/IntegrityUtils.kt +105 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/android/src/main/res/values/styles.xml +5 -0
- package/dist/docs.json +598 -0
- package/dist/esm/definitions.d.ts +554 -0
- package/dist/esm/definitions.js +56 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +15 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +32 -0
- package/dist/esm/web.js +51 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +130 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +133 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/IntegrityPlugin/IntegrityCheckOptions.swift +41 -0
- package/ios/Sources/IntegrityPlugin/IntegrityConfig.swift +135 -0
- package/ios/Sources/IntegrityPlugin/IntegrityEntitlementChecks.swift +58 -0
- package/ios/Sources/IntegrityPlugin/IntegrityError.swift +49 -0
- package/ios/Sources/IntegrityPlugin/IntegrityImpl.swift +397 -0
- package/ios/Sources/IntegrityPlugin/IntegrityPlugin.swift +345 -0
- package/ios/Sources/IntegrityPlugin/IntegrityReportBuilder.swift +184 -0
- package/ios/Sources/IntegrityPlugin/Utils/IntegrityLogger.swift +69 -0
- package/ios/Sources/IntegrityPlugin/Utils/IntegrityUtils.swift +144 -0
- package/ios/Sources/IntegrityPlugin/Version.swift +16 -0
- package/ios/Sources/IntegrityPlugin/filesystem/IntegrityFilesystemChecks.swift +86 -0
- package/ios/Sources/IntegrityPlugin/hook/IntegrityHookChecks.swift +85 -0
- package/ios/Sources/IntegrityPlugin/jailbreak/IntegrityJailbreakDetector.swift +74 -0
- package/ios/Sources/IntegrityPlugin/jailbreak/IntegrityJailbreakUrlSchemeDetector.swift +42 -0
- package/ios/Sources/IntegrityPlugin/remote/IntegrityRemoteAttestor.swift +40 -0
- package/ios/Sources/IntegrityPlugin/runtime/IntegrityRuntimeChecks.swift +63 -0
- package/ios/Sources/IntegrityPlugin/simulator/IntegritySimulatorChecks.swift +20 -0
- package/ios/Sources/IntegrityPlugin/ui/IntegrityBlockViewController.swift +143 -0
- package/ios/Tests/IntegrityPluginTests/IntegrityPluginTests.swift +10 -0
- package/package.json +106 -0
package/README.md
ADDED
|
@@ -0,0 +1,1104 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img
|
|
3
|
+
src="https://raw.githubusercontent.com/cap-kit/capacitor-plugins/main/assets/logo.png"
|
|
4
|
+
alt="CapKit Logo"
|
|
5
|
+
width="128"
|
|
6
|
+
/>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<h3 align="center">Integrity</h3>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<strong>
|
|
13
|
+
<code>@cap-kit/integrity</code>
|
|
14
|
+
</strong>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
<p align="center">
|
|
18
|
+
Runtime integrity and environment signal detection for Capacitor applications.<br>
|
|
19
|
+
Provides <strong>observational signals</strong> about the execution environment,
|
|
20
|
+
such as rooting, jailbreaking, emulators, instrumentation, and basic tampering
|
|
21
|
+
indicators on <strong>Android</strong> and <strong>iOS</strong>.<br><br>
|
|
22
|
+
Designed for <strong>Capacitor v8</strong>, with a stable, platform-agnostic
|
|
23
|
+
JavaScript API and first-class support for
|
|
24
|
+
<strong>Swift Package Manager</strong> and modern Android toolchains.
|
|
25
|
+
</p>
|
|
26
|
+
|
|
27
|
+
<p align="center">
|
|
28
|
+
<a href="https://www.npmjs.com/package/@cap-kit/integrity">
|
|
29
|
+
<img src="https://img.shields.io/npm/v/@cap-kit/integrity?color=blue&label=npm&logo=npm&style=flat-square" alt="npm version">
|
|
30
|
+
</a>
|
|
31
|
+
<a href="https://github.com/cap-kit/capacitor-plugins/actions">
|
|
32
|
+
<img src="https://img.shields.io/github/actions/workflow/status/cap-kit/capacitor-plugins/ci.yml?branch=main&label=CI&logo=github&style=flat-square" alt="CI Status" />
|
|
33
|
+
</a>
|
|
34
|
+
<a href="https://capacitorjs.com/">
|
|
35
|
+
<img src="https://img.shields.io/badge/Capacitor-Plugin-blue?logo=capacitor&style=flat-square" alt="Capacitor Plugin">
|
|
36
|
+
</a>
|
|
37
|
+
<a href="https://www.npmjs.com/package/@cap-kit/integrity">
|
|
38
|
+
<img src="https://img.shields.io/npm/dm/@cap-kit/integrity?style=flat-square" alt="Downloads" />
|
|
39
|
+
</a>
|
|
40
|
+
<a href="./LICENSE">
|
|
41
|
+
<img src="https://img.shields.io/npm/l/@cap-kit/integrity?style=flat-square&logo=open-source-initiative&logoColor=white&color=green" alt="License" />
|
|
42
|
+
</a>
|
|
43
|
+
<img src="https://img.shields.io/maintenance/yes/2026?style=flat-square" alt="Maintained" />
|
|
44
|
+
</p>
|
|
45
|
+
|
|
46
|
+
<br />
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Overview
|
|
51
|
+
|
|
52
|
+
`@cap-kit/integrity` provides **runtime integrity and environment signals**
|
|
53
|
+
for Capacitor applications on **Android** and **iOS**.
|
|
54
|
+
|
|
55
|
+
The plugin performs **best-effort detection** of conditions such as:
|
|
56
|
+
|
|
57
|
+
- Rooted / jailbroken devices
|
|
58
|
+
- Emulators and simulators
|
|
59
|
+
- Debug and instrumentation indicators
|
|
60
|
+
- Basic tampering and repackaging signals
|
|
61
|
+
- Frida and runtime hooking heuristics
|
|
62
|
+
|
|
63
|
+
The plugin **does NOT**:
|
|
64
|
+
|
|
65
|
+
- enforce security policies
|
|
66
|
+
- block or terminate the application
|
|
67
|
+
- present UI automatically
|
|
68
|
+
- guarantee protection against advanced attackers
|
|
69
|
+
|
|
70
|
+
All decisions are explicitly delegated to the **host application**.
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Versioning & Release Policy (IMPORTANT)
|
|
75
|
+
|
|
76
|
+
The `@cap-kit/integrity` plugin is currently under **active development** toward
|
|
77
|
+
a stable `v8.0.0` release.
|
|
78
|
+
|
|
79
|
+
All versions published as `v8.0.0-next.x` are considered:
|
|
80
|
+
|
|
81
|
+
They may include fully production-grade code,
|
|
82
|
+
but are published under the `next` tag to allow
|
|
83
|
+
controlled stabilization and incremental validation.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Security Model (IMPORTANT)
|
|
88
|
+
|
|
89
|
+
This plugin follows an **observational security model**.
|
|
90
|
+
|
|
91
|
+
It reports **signals**, not decisions.
|
|
92
|
+
|
|
93
|
+
- Signals are heuristic observations
|
|
94
|
+
- Signals may produce false positives or false negatives
|
|
95
|
+
- The returned score is **provisional** and **non-normative**
|
|
96
|
+
- Consumers MUST combine signals with business logic
|
|
97
|
+
|
|
98
|
+
> ⚠️ This plugin is **NOT** a replacement for a full RASP or DRM solution.
|
|
99
|
+
|
|
100
|
+
### Internal performance optimizations
|
|
101
|
+
|
|
102
|
+
To reduce repeated execution of expensive integrity checks,
|
|
103
|
+
the plugin applies a short-lived **negative cache** internally.
|
|
104
|
+
|
|
105
|
+
Key characteristics:
|
|
106
|
+
|
|
107
|
+
- Applies only to `standard` and `strict` levels
|
|
108
|
+
- Caches only **clean executions** (no detected signals)
|
|
109
|
+
- Time-to-live: **~30 seconds**
|
|
110
|
+
- Automatically invalidated as soon as any signal is detected
|
|
111
|
+
- Completely transparent to the JavaScript API
|
|
112
|
+
|
|
113
|
+
This optimization improves performance and battery usage
|
|
114
|
+
without affecting detection semantics or signal correctness.
|
|
115
|
+
|
|
116
|
+
> The cache never suppresses or hides detected integrity signals.
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Install
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
pnpm add @cap-kit/integrity
|
|
124
|
+
# or
|
|
125
|
+
npm install @cap-kit/integrity
|
|
126
|
+
# or
|
|
127
|
+
yarn add @cap-kit/integrity
|
|
128
|
+
# then run:
|
|
129
|
+
npx cap sync
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Native Configuration (Optional — Early Boot Enhancement)
|
|
135
|
+
|
|
136
|
+
To capture security signals at the earliest possible stage (before the Capacitor bridge is initialized), you can manually integrate the plugin into your App Host's native entry points. This is highly recommended for detecting advanced threats like Root/Jailbreak or early instrumentation.
|
|
137
|
+
|
|
138
|
+
### When should you use native early boot integration?
|
|
139
|
+
|
|
140
|
+
Native early boot integration is **optional** and exists to improve
|
|
141
|
+
**signal timing**, not signal correctness.
|
|
142
|
+
|
|
143
|
+
You SHOULD consider this integration if:
|
|
144
|
+
|
|
145
|
+
- you want to observe potential root / jailbreak conditions
|
|
146
|
+
**as early as possible**
|
|
147
|
+
- you need visibility into instrumentation that may attach
|
|
148
|
+
before the JavaScript runtime starts
|
|
149
|
+
- you are building high-risk or security-sensitive applications
|
|
150
|
+
|
|
151
|
+
You do NOT need this integration if:
|
|
152
|
+
|
|
153
|
+
- you only require integrity signals during normal runtime
|
|
154
|
+
- you rely exclusively on `Integrity.check()` from JavaScript
|
|
155
|
+
- early detection timing is not critical for your use case
|
|
156
|
+
|
|
157
|
+
### Android Integration
|
|
158
|
+
|
|
159
|
+
In your `MainActivity.kt`, call `IntegrityImpl.onApplicationCreate(context)` inside the `onCreate` method:
|
|
160
|
+
|
|
161
|
+
```diff
|
|
162
|
+
|
|
163
|
+
package io.ionic.starter // Use your actual package name
|
|
164
|
+
|
|
165
|
+
import android.os.Bundle
|
|
166
|
+
import com.getcapacitor.BridgeActivity
|
|
167
|
+
+ import io.capkit.integrity.IntegrityImpl
|
|
168
|
+
|
|
169
|
+
class MainActivity : BridgeActivity() {
|
|
170
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
171
|
+
+ // Capture security signals during early boot
|
|
172
|
+
+ IntegrityImpl.onApplicationCreate(this)
|
|
173
|
+
|
|
174
|
+
super.onCreate(savedInstanceState)
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### iOS Integration
|
|
181
|
+
|
|
182
|
+
In your `AppDelegate.swift`, call `IntegrityImpl.onAppLaunch()` inside the `application(_:didFinishLaunchingWithOptions:)` method:
|
|
183
|
+
|
|
184
|
+
```diff
|
|
185
|
+
|
|
186
|
+
import UIKit
|
|
187
|
+
import Capacitor
|
|
188
|
+
+ import IntegrityPlugin // Import the plugin module
|
|
189
|
+
|
|
190
|
+
@UIApplicationMain
|
|
191
|
+
class AppDelegate: UIResponder, UIApplicationDelegate {
|
|
192
|
+
|
|
193
|
+
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
|
194
|
+
|
|
195
|
+
+ // Capture security signals at the earliest stage possible
|
|
196
|
+
+ IntegrityImpl.onAppLaunch()
|
|
197
|
+
|
|
198
|
+
return true
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
> **Important**
|
|
205
|
+
>
|
|
206
|
+
> If native early boot integration is not performed:
|
|
207
|
+
>
|
|
208
|
+
> - the plugin remains fully functional
|
|
209
|
+
> - no integrity capability is lost
|
|
210
|
+
> - detection simply starts when the JavaScript layer invokes `Integrity.check()`
|
|
211
|
+
>
|
|
212
|
+
> Native integration improves **timing**, not **coverage**.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
### Early boot signals (IMPORTANT)
|
|
217
|
+
|
|
218
|
+
When integrated at the native application entry points
|
|
219
|
+
(`MainActivity.onCreate` on Android, `AppDelegate.didFinishLaunchingWithOptions`
|
|
220
|
+
on iOS), the Integrity plugin may capture **early boot integrity signals**
|
|
221
|
+
before the Capacitor bridge is fully initialized.
|
|
222
|
+
|
|
223
|
+
IMPORTANT NOTES:
|
|
224
|
+
|
|
225
|
+
- Early boot signals are **best-effort** and opportunistic.
|
|
226
|
+
- They are **not guaranteed** to be captured on every app launch.
|
|
227
|
+
- Their absence MUST NOT be interpreted as a clean environment.
|
|
228
|
+
- They may be affected by:
|
|
229
|
+
- process restarts
|
|
230
|
+
- OS-level lifecycle optimizations
|
|
231
|
+
- multi-process behavior (Android)
|
|
232
|
+
- warm launches vs cold starts
|
|
233
|
+
|
|
234
|
+
Behavioral guarantees:
|
|
235
|
+
|
|
236
|
+
- Early boot signals are **merged into the first `Integrity.check()` report**
|
|
237
|
+
when available.
|
|
238
|
+
- If early boot integration is not performed, the plugin continues
|
|
239
|
+
to function correctly without them.
|
|
240
|
+
- Applications MUST NOT rely exclusively on early boot signals
|
|
241
|
+
for security decisions.
|
|
242
|
+
|
|
243
|
+
> Early boot detection improves visibility, not certainty.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Configuration
|
|
248
|
+
|
|
249
|
+
Configuration is **static** and read **natively** from `capacitor.config`.
|
|
250
|
+
|
|
251
|
+
These values are:
|
|
252
|
+
|
|
253
|
+
- read once at plugin initialization
|
|
254
|
+
- immutable at runtime
|
|
255
|
+
- NOT accessible from JavaScript
|
|
256
|
+
|
|
257
|
+
Configuration options for the Integrity plugin.
|
|
258
|
+
|
|
259
|
+
| Prop | Type | Description | Default | Since |
|
|
260
|
+
| ------------------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ----- |
|
|
261
|
+
| **`verboseLogging`** | <code>boolean</code> | Enables verbose native logging. When enabled, additional debug information is printed to the native console (Logcat on Android, Xcode on iOS). This option affects native logging behavior only and has no impact on the JavaScript API or runtime behavior. | <code>false</code> | 8.0.0 |
|
|
262
|
+
| **`blockPage`** | <code>IntegrityBlockPageConfig</code> | Optional configuration for the integrity block page. This configuration controls the availability and source of a developer-provided HTML page that may be presented to the end user when the host application decides to do so. This configuration is: - read only by native code - immutable at runtime - NOT accessible from JavaScript The Integrity plugin will NEVER automatically present the block page. Presentation is always explicitly triggered by the host application via the public API. | | 8.0.0 |
|
|
263
|
+
| **`jailbreakUrlSchemes`** | <code>JailbreakUrlSchemesConfig</code> | Optional configuration for jailbreak URL scheme probing (iOS only). When enabled, the native iOS implementation may probe for known jailbreak-related applications using URL schemes such as `cydia://`. This configuration: - is read natively at runtime - is immutable - is NOT accessible from JavaScript - does NOT alter the public JavaScript API | | 8.0.0 |
|
|
264
|
+
|
|
265
|
+
### Examples
|
|
266
|
+
|
|
267
|
+
In `capacitor.config.json`:
|
|
268
|
+
|
|
269
|
+
```json
|
|
270
|
+
{
|
|
271
|
+
"plugins": {
|
|
272
|
+
"Integrity": {
|
|
273
|
+
"verboseLogging": true,
|
|
274
|
+
"blockPage": {
|
|
275
|
+
"enabled": true,
|
|
276
|
+
"url": "public/integrity-block.html"
|
|
277
|
+
},
|
|
278
|
+
"jailbreakUrlSchemes": {
|
|
279
|
+
"enabled": true,
|
|
280
|
+
"schemes": ["cydia", "sileo", "zbra"]
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
In `capacitor.config.ts`:
|
|
288
|
+
|
|
289
|
+
```ts
|
|
290
|
+
/// <reference types="@cap-kit/integrity" />
|
|
291
|
+
|
|
292
|
+
import { CapacitorConfig } from '@capacitor/cli';
|
|
293
|
+
|
|
294
|
+
const config: CapacitorConfig = {
|
|
295
|
+
plugins: {
|
|
296
|
+
Integrity: {
|
|
297
|
+
verboseLogging: true,
|
|
298
|
+
blockPage: {
|
|
299
|
+
enabled: true,
|
|
300
|
+
url: 'public/integrity-block.html',
|
|
301
|
+
},
|
|
302
|
+
jailbreakUrlSchemes: {
|
|
303
|
+
enabled: true,
|
|
304
|
+
schemes: ['cydia', 'sileo', 'zbra'],
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
export default config;
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
### iOS Jailbreak URL Scheme Probing (Opt-In)
|
|
316
|
+
|
|
317
|
+
The Integrity plugin can optionally probe for known jailbreak-related
|
|
318
|
+
applications using URL schemes such as `cydia://`.
|
|
319
|
+
|
|
320
|
+
This feature is **disabled by default** and must be explicitly enabled
|
|
321
|
+
via native configuration.
|
|
322
|
+
|
|
323
|
+
#### Requirements
|
|
324
|
+
|
|
325
|
+
You MUST declare the queried schemes in `Info.plist`:
|
|
326
|
+
|
|
327
|
+
```xml
|
|
328
|
+
<key>LSApplicationQueriesSchemes</key>
|
|
329
|
+
<array>
|
|
330
|
+
<string>cydia</string>
|
|
331
|
+
<string>sileo</string>
|
|
332
|
+
<string>zbra</string>
|
|
333
|
+
</array>
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## Usage
|
|
339
|
+
|
|
340
|
+
### Basic integrity check
|
|
341
|
+
|
|
342
|
+
```ts
|
|
343
|
+
import { Integrity } from '@cap-kit/integrity';
|
|
344
|
+
|
|
345
|
+
const report = await Integrity.check();
|
|
346
|
+
|
|
347
|
+
if (report.compromised) {
|
|
348
|
+
// Decide what to do
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Integrity check options
|
|
353
|
+
|
|
354
|
+
`Integrity.check()` accepts optional parameters that control
|
|
355
|
+
the strictness and verbosity of the integrity checks.
|
|
356
|
+
|
|
357
|
+
```ts
|
|
358
|
+
const report = await Integrity.check({
|
|
359
|
+
level: 'standard',
|
|
360
|
+
includeDebugInfo: true,
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
#### Options
|
|
365
|
+
|
|
366
|
+
| Option | Type | Default | Description |
|
|
367
|
+
| ------------------ | ----------------------------------- | --------- | ---------------------------------------------------- |
|
|
368
|
+
| `level` | `'basic' \| 'standard' \| 'strict'` | `'basic'` | Controls which categories of checks are executed |
|
|
369
|
+
| `includeDebugInfo` | `boolean` | `false` | Includes diagnostic descriptions in returned signals |
|
|
370
|
+
|
|
371
|
+
#### Levels behavior
|
|
372
|
+
|
|
373
|
+
- **basic**
|
|
374
|
+
- Root / jailbreak detection
|
|
375
|
+
- Emulator / simulator detection
|
|
376
|
+
|
|
377
|
+
- **standard**
|
|
378
|
+
- All `basic` checks
|
|
379
|
+
- Debugger / debug build detection
|
|
380
|
+
- Instrumentation / hooking heuristics (Frida, Substrate)
|
|
381
|
+
- **Memory map & Runtime image inspection**
|
|
382
|
+
- **Heuristic signal correlation**
|
|
383
|
+
|
|
384
|
+
- **strict**
|
|
385
|
+
- All `standard` checks
|
|
386
|
+
- Additional tamper and integrity heuristics
|
|
387
|
+
- Explicit reporting of unavailable platform attestation (observational only)
|
|
388
|
+
|
|
389
|
+
> ⚠️ The returned integrity score remains provisional and
|
|
390
|
+
> must not be used as the sole security decision signal.
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
### Presenting a block / warning page
|
|
395
|
+
|
|
396
|
+
The plugin will **never** present UI automatically.
|
|
397
|
+
|
|
398
|
+
UI presentation is always explicitly triggered by the host application.
|
|
399
|
+
|
|
400
|
+
```ts
|
|
401
|
+
await Integrity.presentBlockPage({
|
|
402
|
+
reason: 'integrity_failed',
|
|
403
|
+
});
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
#### Dismissible block page (optional)
|
|
407
|
+
|
|
408
|
+
By default, the block page is **not dismissible** (secure-by-default).
|
|
409
|
+
|
|
410
|
+
For demos, testing, or controlled environments, dismissal can be explicitly enabled:
|
|
411
|
+
|
|
412
|
+
```ts
|
|
413
|
+
await Integrity.presentBlockPage({
|
|
414
|
+
reason: 'integrity_failed',
|
|
415
|
+
dismissible: true,
|
|
416
|
+
});
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
Platform behavior:
|
|
420
|
+
|
|
421
|
+
| Platform | dismissible = false | dismissible = true |
|
|
422
|
+
| -------- | ---------------------- | ------------------------------- |
|
|
423
|
+
| Android | Back & close disabled | Native close button + back |
|
|
424
|
+
| iOS | Swipe & close disabled | Swipe-to-dismiss + native close |
|
|
425
|
+
| Web | Not supported | Not supported |
|
|
426
|
+
|
|
427
|
+
> ⚠️ In production environments, it is recommended to keep `dismissible` disabled.
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## Error Handling
|
|
432
|
+
|
|
433
|
+
All Integrity methods use **Promise rejection** for error handling.
|
|
434
|
+
|
|
435
|
+
Errors are returned as a structured object:
|
|
436
|
+
|
|
437
|
+
```ts
|
|
438
|
+
{
|
|
439
|
+
message: string;
|
|
440
|
+
code: IntegrityErrorCode;
|
|
441
|
+
}
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
Error handling is **consistent across Android, iOS, and Web**.
|
|
445
|
+
|
|
446
|
+
### Example
|
|
447
|
+
|
|
448
|
+
```ts
|
|
449
|
+
import { Integrity, IntegrityErrorCode } from '@cap-kit/integrity';
|
|
450
|
+
|
|
451
|
+
try {
|
|
452
|
+
await Integrity.check();
|
|
453
|
+
} catch (e) {
|
|
454
|
+
if (e.code === IntegrityErrorCode.UNAVAILABLE) {
|
|
455
|
+
// Feature not available on this platform
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
### Score Explanation Metadata
|
|
463
|
+
|
|
464
|
+
The Integrity plugin may include an optional `scoreExplanation`
|
|
465
|
+
field in the integrity report.
|
|
466
|
+
|
|
467
|
+
This field provides transparency about how the integrity score
|
|
468
|
+
was derived from detected signals.
|
|
469
|
+
|
|
470
|
+
#### Important notes
|
|
471
|
+
|
|
472
|
+
- This metadata is informational only.
|
|
473
|
+
- It does NOT alter the integrity score.
|
|
474
|
+
- It MUST NOT be treated as a security decision.
|
|
475
|
+
- Individual signals remain the authoritative source of truth.
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
## Web Platform Notes
|
|
480
|
+
|
|
481
|
+
The Web platform is supported to preserve API parity.
|
|
482
|
+
|
|
483
|
+
However, native integrity checks are **not available** in browser environments.
|
|
484
|
+
|
|
485
|
+
The following methods will reject with `IntegrityErrorCode.UNAVAILABLE` on Web:
|
|
486
|
+
|
|
487
|
+
- `Integrity.check()`
|
|
488
|
+
- `Integrity.presentBlockPage()`
|
|
489
|
+
|
|
490
|
+
`Integrity.getPluginVersion()` is always available.
|
|
491
|
+
|
|
492
|
+
---
|
|
493
|
+
|
|
494
|
+
## Permissions
|
|
495
|
+
|
|
496
|
+
### Android
|
|
497
|
+
|
|
498
|
+
On Android, this plugin requires the `android.permission.INTERNET` permission. This permission is necessary for internal integrity checks, specifically for attempting socket connections to `localhost` with a controlled timeout to detect hooking frameworks like Frida.
|
|
499
|
+
|
|
500
|
+
This permission is automatically added to your `AndroidManifest.xml` via the plugin's native configuration.
|
|
501
|
+
|
|
502
|
+
#### Package Visibility (Android 11+)
|
|
503
|
+
|
|
504
|
+
To perform expanded root detection (scanning for apps like Magisk or SuperUser), the plugin declares a `<queries>` block in its manifest. This allow-list is required by Google Play policies to "see" security-related packages on devices with API level 30+.
|
|
505
|
+
|
|
506
|
+
**Note:** If your app is submitted to Google Play, you may need to justify the use of this expanded visibility during the app review process if you are targeting security-sensitive functionality.
|
|
507
|
+
|
|
508
|
+
### iOS
|
|
509
|
+
|
|
510
|
+
No additional runtime permissions are required for iOS.
|
|
511
|
+
|
|
512
|
+
#### ⚠️ Toolchain Requirement
|
|
513
|
+
|
|
514
|
+
This plugin is designed exclusively for **Capacitor v8**. In accordance with the global strict rules for this version, **Xcode 26 is the MANDATORY requirement** for building the iOS native implementation.
|
|
515
|
+
|
|
516
|
+
Any issues or behaviors observed on Xcode 15, 16, or earlier versions are considered environment misconfigurations and are not supported by the plugin.
|
|
517
|
+
|
|
518
|
+
---
|
|
519
|
+
|
|
520
|
+
## API
|
|
521
|
+
|
|
522
|
+
The public API is fully typed and documented via TypeScript definitions.
|
|
523
|
+
|
|
524
|
+
See `definitions.ts` for the complete contract.
|
|
525
|
+
|
|
526
|
+
<docgen-index>
|
|
527
|
+
|
|
528
|
+
* [`check(...)`](#check)
|
|
529
|
+
* [`presentBlockPage(...)`](#presentblockpage)
|
|
530
|
+
* [`getPluginVersion()`](#getpluginversion)
|
|
531
|
+
* [`addListener('integritySignal', ...)`](#addlistenerintegritysignal-)
|
|
532
|
+
* [`removeAllListeners()`](#removealllisteners)
|
|
533
|
+
* [Interfaces](#interfaces)
|
|
534
|
+
* [Type Aliases](#type-aliases)
|
|
535
|
+
* [Enums](#enums)
|
|
536
|
+
|
|
537
|
+
</docgen-index>
|
|
538
|
+
|
|
539
|
+
<docgen-api>
|
|
540
|
+
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
|
|
541
|
+
|
|
542
|
+
Public JavaScript API for the Integrity Capacitor plugin.
|
|
543
|
+
|
|
544
|
+
This interface defines a stable, platform-agnostic API.
|
|
545
|
+
All methods behave consistently across Android, iOS, and Web.
|
|
546
|
+
|
|
547
|
+
### check(...)
|
|
548
|
+
|
|
549
|
+
```typescript
|
|
550
|
+
check(options?: IntegrityCheckOptions | undefined) => Promise<IntegrityReport>
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
Executes a runtime integrity check.
|
|
554
|
+
|
|
555
|
+
| Param | Type |
|
|
556
|
+
| ------------- | ----------------------------------------------------------------------- |
|
|
557
|
+
| **`options`** | <code><a href="#integritycheckoptions">IntegrityCheckOptions</a></code> |
|
|
558
|
+
|
|
559
|
+
**Returns:** <code>Promise<<a href="#integrityreport">IntegrityReport</a>></code>
|
|
560
|
+
|
|
561
|
+
**Since:** 8.0.0
|
|
562
|
+
|
|
563
|
+
#### Example
|
|
564
|
+
|
|
565
|
+
```ts
|
|
566
|
+
const report = await Integrity.check();
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
--------------------
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
### presentBlockPage(...)
|
|
573
|
+
|
|
574
|
+
```typescript
|
|
575
|
+
presentBlockPage(options?: PresentBlockPageOptions | undefined) => Promise<PresentBlockPageResult>
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
Presents the configured integrity block page, if enabled.
|
|
579
|
+
|
|
580
|
+
The plugin never decides *when* this method should be called.
|
|
581
|
+
Invocation is entirely controlled by the host application.
|
|
582
|
+
|
|
583
|
+
| Param | Type |
|
|
584
|
+
| ------------- | --------------------------------------------------------------------------- |
|
|
585
|
+
| **`options`** | <code><a href="#presentblockpageoptions">PresentBlockPageOptions</a></code> |
|
|
586
|
+
|
|
587
|
+
**Returns:** <code>Promise<<a href="#presentblockpageresult">PresentBlockPageResult</a>></code>
|
|
588
|
+
|
|
589
|
+
**Since:** 8.0.0
|
|
590
|
+
|
|
591
|
+
#### Example
|
|
592
|
+
|
|
593
|
+
```ts
|
|
594
|
+
await Integrity.presentBlockPage({ reason: 'integrity_failed' });
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
--------------------
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
### getPluginVersion()
|
|
601
|
+
|
|
602
|
+
```typescript
|
|
603
|
+
getPluginVersion() => Promise<PluginVersionResult>
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
Returns the native plugin version.
|
|
607
|
+
|
|
608
|
+
The returned version corresponds to the native implementation
|
|
609
|
+
bundled with the application.
|
|
610
|
+
|
|
611
|
+
**Returns:** <code>Promise<<a href="#pluginversionresult">PluginVersionResult</a>></code>
|
|
612
|
+
|
|
613
|
+
**Since:** 8.0.0
|
|
614
|
+
|
|
615
|
+
#### Example
|
|
616
|
+
|
|
617
|
+
```ts
|
|
618
|
+
const { version } = await Integrity.getPluginVersion();
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
--------------------
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
### addListener('integritySignal', ...)
|
|
625
|
+
|
|
626
|
+
```typescript
|
|
627
|
+
addListener(eventName: 'integritySignal', listenerFunc: (signal: IntegritySignalEvent) => void) => Promise<PluginListenerHandle>
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
Registers a listener for real-time integrity signals.
|
|
631
|
+
|
|
632
|
+
The provided callback is invoked every time a new integrity
|
|
633
|
+
signal is detected by the native layer.
|
|
634
|
+
|
|
635
|
+
BEHAVIOR:
|
|
636
|
+
- Signals may be emitted at any time after plugin initialization.
|
|
637
|
+
- Signals detected before listener registration MAY be delivered
|
|
638
|
+
immediately after registration.
|
|
639
|
+
- No guarantees are made about signal frequency or ordering
|
|
640
|
+
across platforms.
|
|
641
|
+
|
|
642
|
+
IMPORTANT:
|
|
643
|
+
- This listener is non-blocking.
|
|
644
|
+
- The plugin does NOT enforce any policy based on signals.
|
|
645
|
+
|
|
646
|
+
| Param | Type | Description |
|
|
647
|
+
| ------------------ | -------------------------------------------------------------------------------- | -------------------------------------------- |
|
|
648
|
+
| **`eventName`** | <code>'integritySignal'</code> | The event to listen for ('integritySignal'). |
|
|
649
|
+
| **`listenerFunc`** | <code>(signal: <a href="#integritysignal">IntegritySignal</a>) => void</code> | Callback invoked with the detected signal. |
|
|
650
|
+
|
|
651
|
+
**Returns:** <code>Promise<<a href="#pluginlistenerhandle">PluginListenerHandle</a>></code>
|
|
652
|
+
|
|
653
|
+
**Since:** 8.0.0
|
|
654
|
+
|
|
655
|
+
--------------------
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
### removeAllListeners()
|
|
659
|
+
|
|
660
|
+
```typescript
|
|
661
|
+
removeAllListeners() => Promise<void>
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
Removes all registered listeners for this plugin.
|
|
665
|
+
|
|
666
|
+
NOTE:
|
|
667
|
+
- Removing listeners does NOT stop signal detection natively.
|
|
668
|
+
- Signals may continue to be detected and buffered
|
|
669
|
+
until a listener is registered again.
|
|
670
|
+
|
|
671
|
+
**Since:** 8.0.0
|
|
672
|
+
|
|
673
|
+
--------------------
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
### Interfaces
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
#### IntegrityReport
|
|
680
|
+
|
|
681
|
+
Result object returned by `Integrity.check()`.
|
|
682
|
+
|
|
683
|
+
This object aggregates all detected signals
|
|
684
|
+
and provides a provisional integrity score.
|
|
685
|
+
|
|
686
|
+
| Prop | Type | Description | Since |
|
|
687
|
+
| ---------------------- | ------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
|
|
688
|
+
| **`compromised`** | <code>boolean</code> | Indicates whether the environment is considered compromised according to the current scoring model. | |
|
|
689
|
+
| **`score`** | <code>number</code> | Provisional integrity score. The score ranges from 0 to 100 and is derived from the detected signals. | |
|
|
690
|
+
| **`signals`** | <code>IntegritySignal[]</code> | List of detected integrity signals. | |
|
|
691
|
+
| **`environment`** | <code><a href="#integrityenvironment">IntegrityEnvironment</a></code> | Execution environment summary. | |
|
|
692
|
+
| **`timestamp`** | <code>number</code> | Unix timestamp (milliseconds) when the check was performed. | |
|
|
693
|
+
| **`scoreExplanation`** | <code><a href="#integrityscoreexplanation">IntegrityScoreExplanation</a></code> | Optional explanation metadata describing how the integrity score was derived from the detected signals. This field is informational only and MUST NOT be treated as a security decision or enforcement mechanism. | 8.0.0 |
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
#### IntegritySignal
|
|
697
|
+
|
|
698
|
+
A single integrity signal detected on the current device.
|
|
699
|
+
|
|
700
|
+
Signals represent *observations*, not decisions.
|
|
701
|
+
Multiple signals MAY be combined by the host application
|
|
702
|
+
to derive a security policy.
|
|
703
|
+
|
|
704
|
+
Signals:
|
|
705
|
+
- are emitted asynchronously
|
|
706
|
+
- may occur at any time during the app lifecycle
|
|
707
|
+
- may be emitted before or after the first call to `check()`
|
|
708
|
+
|
|
709
|
+
| Prop | Type | Description |
|
|
710
|
+
| ----------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
711
|
+
| **`id`** | <code>string</code> | Stable identifier for the signal. This value: - is stable across releases - MUST NOT be parsed or pattern-matched - is intended for analytics, logging, and policy evaluation |
|
|
712
|
+
| **`category`** | <code><a href="#integritysignalcategory">IntegritySignalCategory</a></code> | High-level category of the signal. Categories allow grouping related signals without relying on specific identifiers. |
|
|
713
|
+
| **`confidence`** | <code><a href="#integrityconfidencelevel">IntegrityConfidenceLevel</a></code> | Confidence level of the detection. This value expresses how strongly the signal correlates with a potentially compromised or risky environment. NOTE: Although typed as a string union in the public API, native implementations MUST only emit values defined by the internal <a href="#integrityconfidencelevel">IntegrityConfidenceLevel</a> enum. |
|
|
714
|
+
| **`description`** | <code>string</code> | Optional human-readable description. This field: - is intended for diagnostics and debugging only - MAY be omitted or redacted in production builds - MUST NOT be relied upon programmatically |
|
|
715
|
+
| **`metadata`** | <code>Record<string, string \| number \| boolean></code> | Additional diagnostic metadata associated with the signal. Metadata provides granular details about the detection (e.g. matched filesystem paths, runtime artifacts, or environment properties) without altering the stable signal identifier. IMPORTANT: - Metadata is informational only. - Keys and values are NOT guaranteed to be stable. - Applications MUST NOT rely on specific metadata fields for security decisions. |
|
|
716
|
+
|
|
717
|
+
|
|
718
|
+
#### IntegrityEnvironment
|
|
719
|
+
|
|
720
|
+
Summary of the execution environment in which
|
|
721
|
+
the integrity check was performed.
|
|
722
|
+
|
|
723
|
+
| Prop | Type | Description |
|
|
724
|
+
| ------------------ | ---------------------------------------- | ----------------------------------------------------------------------------- |
|
|
725
|
+
| **`platform`** | <code>'ios' \| 'android' \| 'web'</code> | Current platform. |
|
|
726
|
+
| **`isEmulator`** | <code>boolean</code> | Indicates whether the app is running in an emulator or simulator environment. |
|
|
727
|
+
| **`isDebugBuild`** | <code>boolean</code> | Indicates whether the app was built in debug/development mode. |
|
|
728
|
+
|
|
729
|
+
|
|
730
|
+
#### IntegrityScoreExplanation
|
|
731
|
+
|
|
732
|
+
Describes how the integrity score was derived.
|
|
733
|
+
|
|
734
|
+
This structure provides transparency and auditability
|
|
735
|
+
without exposing internal scoring algorithms.
|
|
736
|
+
|
|
737
|
+
| Prop | Type | Description |
|
|
738
|
+
| ------------------ | ----------------------------------------------------------- | --------------------------------------------------------- |
|
|
739
|
+
| **`totalSignals`** | <code>number</code> | Total number of detected signals. |
|
|
740
|
+
| **`byConfidence`** | <code>{ high: number; medium: number; low: number; }</code> | Breakdown of signals by confidence level. |
|
|
741
|
+
| **`contributors`** | <code>string[]</code> | List of signal identifiers that contributed to the score. |
|
|
742
|
+
|
|
743
|
+
|
|
744
|
+
#### IntegrityCheckOptions
|
|
745
|
+
|
|
746
|
+
Options controlling the behavior of `Integrity.check()`.
|
|
747
|
+
|
|
748
|
+
These options influence *how* checks are performed,
|
|
749
|
+
not *what* the public API returns.
|
|
750
|
+
|
|
751
|
+
| Prop | Type | Description |
|
|
752
|
+
| ---------------------- | ---------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
753
|
+
| **`level`** | <code>'basic' \| 'standard' \| 'strict'</code> | Desired strictness level. Higher levels may enable additional heuristics at the cost of performance. |
|
|
754
|
+
| **`includeDebugInfo`** | <code>boolean</code> | Includes additional debug information in the returned signals when enabled. |
|
|
755
|
+
|
|
756
|
+
|
|
757
|
+
#### PresentBlockPageResult
|
|
758
|
+
|
|
759
|
+
Result object returned by `presentBlockPage()`.
|
|
760
|
+
|
|
761
|
+
| Prop | Type | Description |
|
|
762
|
+
| --------------- | -------------------- | -------------------------------------------------------- |
|
|
763
|
+
| **`presented`** | <code>boolean</code> | Indicates whether the block page was actually presented. |
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
#### PresentBlockPageOptions
|
|
767
|
+
|
|
768
|
+
Options for presenting the integrity block page.
|
|
769
|
+
|
|
770
|
+
| Prop | Type | Description | Default | Since |
|
|
771
|
+
| ----------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------ | ----- |
|
|
772
|
+
| **`reason`** | <code>string</code> | Optional reason code passed to the block page. This value may be used for analytics, localization, or user messaging. | | 8.0.0 |
|
|
773
|
+
| **`dismissible`** | <code>boolean</code> | Whether the block page can be dismissed by the user. Defaults to false. In production environments, this should typically remain disabled. | <code>false</code> | 8.0.0 |
|
|
774
|
+
|
|
775
|
+
|
|
776
|
+
#### PluginVersionResult
|
|
777
|
+
|
|
778
|
+
Result returned by the getPluginVersion method.
|
|
779
|
+
|
|
780
|
+
| Prop | Type | Description |
|
|
781
|
+
| ------------- | ------------------- | ---------------------------------------- |
|
|
782
|
+
| **`version`** | <code>string</code> | The native version string of the plugin. |
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
#### PluginListenerHandle
|
|
786
|
+
|
|
787
|
+
| Prop | Type |
|
|
788
|
+
| ------------ | ----------------------------------------- |
|
|
789
|
+
| **`remove`** | <code>() => Promise<void></code> |
|
|
790
|
+
|
|
791
|
+
|
|
792
|
+
### Type Aliases
|
|
793
|
+
|
|
794
|
+
|
|
795
|
+
#### IntegritySignalCategory
|
|
796
|
+
|
|
797
|
+
Category of a detected integrity signal.
|
|
798
|
+
|
|
799
|
+
Categories are intentionally broad and stable.
|
|
800
|
+
New detection techniques MUST reuse existing categories
|
|
801
|
+
whenever possible to avoid breaking consumers.
|
|
802
|
+
|
|
803
|
+
<code>'root' | 'jailbreak' | 'emulator' | 'debug' | 'hook' | 'tamper' | 'environment'</code>
|
|
804
|
+
|
|
805
|
+
|
|
806
|
+
#### IntegritySignalEvent
|
|
807
|
+
|
|
808
|
+
Event payload emitted when a new integrity signal is detected.
|
|
809
|
+
|
|
810
|
+
This event represents a *real-time observation* of a potential
|
|
811
|
+
integrity-relevant condition on the device.
|
|
812
|
+
|
|
813
|
+
IMPORTANT:
|
|
814
|
+
- Signals are observational only.
|
|
815
|
+
- Emitting a signal does NOT imply that the environment is compromised.
|
|
816
|
+
- No blocking or enforcement is performed by the plugin.
|
|
817
|
+
|
|
818
|
+
The host application is responsible for:
|
|
819
|
+
- interpreting signals
|
|
820
|
+
- correlating multiple signals
|
|
821
|
+
- applying any security or UX policy
|
|
822
|
+
|
|
823
|
+
<code><a href="#integritysignal">IntegritySignal</a></code>
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
### Enums
|
|
827
|
+
|
|
828
|
+
|
|
829
|
+
#### IntegrityConfidenceLevel
|
|
830
|
+
|
|
831
|
+
| Members | Value |
|
|
832
|
+
| ------------ | --------------------- |
|
|
833
|
+
| **`LOW`** | <code>'low'</code> |
|
|
834
|
+
| **`MEDIUM`** | <code>'medium'</code> |
|
|
835
|
+
| **`HIGH`** | <code>'high'</code> |
|
|
836
|
+
|
|
837
|
+
</docgen-api>
|
|
838
|
+
|
|
839
|
+
---
|
|
840
|
+
|
|
841
|
+
## Integrity events semantics (IMPORTANT)
|
|
842
|
+
|
|
843
|
+
The `integritySignal` event documented above represents a
|
|
844
|
+
**real-time observational snapshot**, not an incremental update.
|
|
845
|
+
|
|
846
|
+
Important clarifications:
|
|
847
|
+
|
|
848
|
+
- Integrity events **may include signals already returned**
|
|
849
|
+
by a previous `Integrity.check()` call.
|
|
850
|
+
- Events are **NOT incremental** and **NOT deltas**.
|
|
851
|
+
- Each emitted event is a **standalone integrity observation**
|
|
852
|
+
produced at a specific moment in time.
|
|
853
|
+
|
|
854
|
+
Implications for applications:
|
|
855
|
+
|
|
856
|
+
- Consumers MUST be prepared to receive duplicate signals.
|
|
857
|
+
- Applications SHOULD implement their own de-duplication or
|
|
858
|
+
correlation logic if required.
|
|
859
|
+
- Events MUST NOT be interpreted as a continuous stream of
|
|
860
|
+
unique integrity changes.
|
|
861
|
+
|
|
862
|
+
> Events report observations, not transitions.
|
|
863
|
+
|
|
864
|
+
---
|
|
865
|
+
|
|
866
|
+
### Cross-correlation: Jailbreak + Hooking (iOS)
|
|
867
|
+
|
|
868
|
+
The Integrity plugin may emit a derived signal when it detects
|
|
869
|
+
both jailbreak indicators and runtime hooking signals during
|
|
870
|
+
the same execution window.
|
|
871
|
+
|
|
872
|
+
This signal represents a **cross-category correlation**, indicating
|
|
873
|
+
that the device is not only modified but also actively instrumented.
|
|
874
|
+
|
|
875
|
+
#### Signal details
|
|
876
|
+
|
|
877
|
+
- **id**: `ios_jailbreak_and_hook_detected`
|
|
878
|
+
- **category**: `tamper`
|
|
879
|
+
- **confidence**: `high`
|
|
880
|
+
|
|
881
|
+
#### Important notes
|
|
882
|
+
|
|
883
|
+
- This signal is observational only.
|
|
884
|
+
- It does not replace or suppress individual signals.
|
|
885
|
+
- It must not be treated as an automatic enforcement trigger.
|
|
886
|
+
|
|
887
|
+
---
|
|
888
|
+
|
|
889
|
+
## Limitations
|
|
890
|
+
|
|
891
|
+
- **Heuristic Bypass**: Root / jailbreak detection can be bypassed by advanced cloaking tools.
|
|
892
|
+
- **Package Scanning**: Root detection on Android includes scanning for known management apps (e.g., Magisk). This is subject to OS-level package visibility restrictions.
|
|
893
|
+
- **Emulator Detection**: Detection is heuristic and relies on build properties that may vary between providers.
|
|
894
|
+
- Frida detection uses memory and runtime inspection
|
|
895
|
+
- **No cryptographic or remote attestation is performed**
|
|
896
|
+
- **Apple App Attest and Google Play Integrity are NOT implemented**
|
|
897
|
+
- Attestation-related signals, when present, explicitly report unavailability
|
|
898
|
+
- No device identity is established
|
|
899
|
+
|
|
900
|
+
These limitations are **intentional** to:
|
|
901
|
+
|
|
902
|
+
- avoid store policy violations
|
|
903
|
+
- reduce false positives
|
|
904
|
+
- keep the plugin portable and maintainable
|
|
905
|
+
|
|
906
|
+
### Debug environment detection
|
|
907
|
+
|
|
908
|
+
The plugin provides parity between platforms for debug detection. A `debug` integrity signal is reported when:
|
|
909
|
+
|
|
910
|
+
- **Debugger Attached**: A debugger is currently attached to the running process (detected via `Debug.isDebuggerConnected()` on Android or `sysctl` on iOS).
|
|
911
|
+
- **Debuggable Environment**: The application is running in a debuggable state or signed with a development profile (detected via `FLAG_DEBUGGABLE` on Android or `get-task-allow` entitlement on iOS).
|
|
912
|
+
|
|
913
|
+
This signal is **informational only** and does not necessarily
|
|
914
|
+
indicate a compromised device.
|
|
915
|
+
|
|
916
|
+
Consumers MUST interpret debug signals in context and
|
|
917
|
+
combine them with other integrity signals.
|
|
918
|
+
|
|
919
|
+
### Hooking detection signal behavior (iOS)
|
|
920
|
+
|
|
921
|
+
On iOS, runtime hooking detection is intentionally designed to emit
|
|
922
|
+
**at most one hooking-related signal per check execution**.
|
|
923
|
+
|
|
924
|
+
Design characteristics:
|
|
925
|
+
|
|
926
|
+
- The detector stops at the **first confirmed hooking artifact**.
|
|
927
|
+
- Only a single signal is emitted, even if multiple suspicious
|
|
928
|
+
libraries or runtime indicators are present.
|
|
929
|
+
- This behavior is **intentional** and optimized for:
|
|
930
|
+
- low noise
|
|
931
|
+
- predictable signal volume
|
|
932
|
+
- reduced false-positive amplification
|
|
933
|
+
|
|
934
|
+
Implications:
|
|
935
|
+
|
|
936
|
+
- The absence of multiple hooking signals does **not** imply
|
|
937
|
+
that only one artifact was present.
|
|
938
|
+
- Diagnostic depth is intentionally limited in favor of
|
|
939
|
+
stability and signal clarity.
|
|
940
|
+
|
|
941
|
+
> This is a design choice, not a detection limitation.
|
|
942
|
+
|
|
943
|
+
---
|
|
944
|
+
|
|
945
|
+
## 🔒 Integrity philosophy
|
|
946
|
+
|
|
947
|
+
### Observation, not enforcement
|
|
948
|
+
|
|
949
|
+
The Integrity plugin is designed as an **observation layer**, not as an enforcement or decision engine.
|
|
950
|
+
|
|
951
|
+
Its responsibility is to **detect and report runtime integrity signals** in a consistent, cross-platform way.
|
|
952
|
+
It deliberately **does not decide what action should be taken** when a signal is detected.
|
|
953
|
+
|
|
954
|
+
This design allows applications to:
|
|
955
|
+
|
|
956
|
+
- define their own security policies
|
|
957
|
+
- adapt behavior to different environments
|
|
958
|
+
- avoid hard-coded or platform-specific assumptions
|
|
959
|
+
|
|
960
|
+
In short:
|
|
961
|
+
|
|
962
|
+
> **The plugin observes.
|
|
963
|
+
> The application decides.**
|
|
964
|
+
|
|
965
|
+
---
|
|
966
|
+
|
|
967
|
+
## 🧩 Why there are no single-purpose checks
|
|
968
|
+
|
|
969
|
+
The public API intentionally exposes a **single entry point**:
|
|
970
|
+
|
|
971
|
+
```ts
|
|
972
|
+
Integrity.check(options?)
|
|
973
|
+
```
|
|
974
|
+
|
|
975
|
+
Rather than providing individual methods such as:
|
|
976
|
+
|
|
977
|
+
- `checkRoot()`
|
|
978
|
+
- `checkEmulator()`
|
|
979
|
+
- `checkDebug()`
|
|
980
|
+
|
|
981
|
+
the plugin returns a **structured integrity report** containing multiple **signals**, each classified by:
|
|
982
|
+
|
|
983
|
+
- category (e.g. root, emulator, debug, hook, tamper)
|
|
984
|
+
- confidence level (low / medium / high)
|
|
985
|
+
|
|
986
|
+
This approach avoids:
|
|
987
|
+
|
|
988
|
+
- API fragmentation
|
|
989
|
+
- platform-specific behavior leaks
|
|
990
|
+
- misuse of isolated checks
|
|
991
|
+
- rigid or unsafe security decisions
|
|
992
|
+
|
|
993
|
+
Applications can still derive fine-grained logic by inspecting the returned signals:
|
|
994
|
+
|
|
995
|
+
```ts
|
|
996
|
+
const hasRoot = report.signals.some((s) => s.category === 'root');
|
|
997
|
+
const hasEmulator = report.signals.some((s) => s.category === 'emulator');
|
|
998
|
+
```
|
|
999
|
+
|
|
1000
|
+
This keeps the API **stable, extensible, and policy-agnostic**.
|
|
1001
|
+
|
|
1002
|
+
---
|
|
1003
|
+
|
|
1004
|
+
## 🧠 Integrity levels
|
|
1005
|
+
|
|
1006
|
+
Instead of selecting individual checks, applications choose a **strictness level**:
|
|
1007
|
+
|
|
1008
|
+
- **basic** – lightweight and safe checks
|
|
1009
|
+
- **standard** – includes debug and hooking detection
|
|
1010
|
+
- **strict** – adds tampering and signature integrity checks
|
|
1011
|
+
|
|
1012
|
+
The selected level controls **how deeply the environment is inspected**, not which single signal is exposed.
|
|
1013
|
+
|
|
1014
|
+
---
|
|
1015
|
+
|
|
1016
|
+
## Score interpretation (IMPORTANT)
|
|
1017
|
+
|
|
1018
|
+
The integrity `score` returned by `Integrity.check()` is a **heuristic indicator**, not a guarantee.
|
|
1019
|
+
|
|
1020
|
+
Key points:
|
|
1021
|
+
|
|
1022
|
+
- The score is derived from detected integrity signals and their confidence levels.
|
|
1023
|
+
- A score **greater than or equal to 30** currently marks the environment as `compromised`.
|
|
1024
|
+
- This threshold is **internal, heuristic-based, and subject to change**.
|
|
1025
|
+
- The score **must NOT** be treated as:
|
|
1026
|
+
- a security guarantee
|
|
1027
|
+
- a cryptographic proof
|
|
1028
|
+
- a definitive compromise verdict
|
|
1029
|
+
|
|
1030
|
+
Applications MUST:
|
|
1031
|
+
|
|
1032
|
+
- interpret the score in context
|
|
1033
|
+
- combine it with individual signals
|
|
1034
|
+
- apply their own business or security logic
|
|
1035
|
+
|
|
1036
|
+
> ⚠️ Do not rely on the score alone to make irreversible security decisions.
|
|
1037
|
+
|
|
1038
|
+
---
|
|
1039
|
+
|
|
1040
|
+
## 🔮 Future extensibility
|
|
1041
|
+
|
|
1042
|
+
The current API focuses on a clean and minimal surface, but the architecture is designed to be **extensible**.
|
|
1043
|
+
|
|
1044
|
+
In the future, the plugin may introduce:
|
|
1045
|
+
|
|
1046
|
+
- more advanced signal classification
|
|
1047
|
+
- additional integrity signals
|
|
1048
|
+
- configurable inclusion or exclusion of signal groups
|
|
1049
|
+
- richer metadata for diagnostics and auditing
|
|
1050
|
+
|
|
1051
|
+
Any future extension will preserve the same core principle:
|
|
1052
|
+
|
|
1053
|
+
- **one entry point**
|
|
1054
|
+
- **no forced policy**
|
|
1055
|
+
- **no platform-specific leakage**
|
|
1056
|
+
|
|
1057
|
+
Applications should always remain in full control of how integrity information is interpreted and enforced.
|
|
1058
|
+
|
|
1059
|
+
---
|
|
1060
|
+
|
|
1061
|
+
## ✅ Summary
|
|
1062
|
+
|
|
1063
|
+
- The Integrity plugin **detects signals**, it does not block or enforce
|
|
1064
|
+
- Security decisions are **always owned by the application**
|
|
1065
|
+
- The API is designed for **long-term stability and flexibility**
|
|
1066
|
+
- Future enhancements will extend capabilities without breaking this model
|
|
1067
|
+
|
|
1068
|
+
---
|
|
1069
|
+
|
|
1070
|
+
## Roadmap (Non-binding)
|
|
1071
|
+
|
|
1072
|
+
> The roadmap below is indicative and non-binding.
|
|
1073
|
+
> Items may be implemented across multiple `next.x` iterations.
|
|
1074
|
+
|
|
1075
|
+
- Optional platform attestation helpers
|
|
1076
|
+
- Extended tamper heuristics
|
|
1077
|
+
- Improved scoring models
|
|
1078
|
+
- Documentation examples
|
|
1079
|
+
|
|
1080
|
+
---
|
|
1081
|
+
|
|
1082
|
+
## Contributing
|
|
1083
|
+
|
|
1084
|
+
Contributions are welcome! Please read the
|
|
1085
|
+
[contributing guide](CONTRIBUTING.md)
|
|
1086
|
+
before submitting a pull request.
|
|
1087
|
+
|
|
1088
|
+
---
|
|
1089
|
+
|
|
1090
|
+
## Credits
|
|
1091
|
+
|
|
1092
|
+
This plugin is based on prior work from the Community and
|
|
1093
|
+
has been refactored and modernized for **Capacitor v8** and
|
|
1094
|
+
**Swift Package Manager** compatibility.
|
|
1095
|
+
|
|
1096
|
+
Original inspiration:
|
|
1097
|
+
|
|
1098
|
+
- [https://github.com/capacitor-community/device-security-detect](https://github.com/capacitor-community/device-security-detect)
|
|
1099
|
+
|
|
1100
|
+
---
|
|
1101
|
+
|
|
1102
|
+
## License
|
|
1103
|
+
|
|
1104
|
+
MIT
|