@gatekeeperx/cordova-plugin-devicex 1.2.5

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/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+ ## [1.0.0] - 2026-01-19
3
+ ### Added
4
+ - Initial release
5
+ - Android support with cordova-android >= 11
6
+ - Pre-compiled AAR bridge (Kotlin)
7
+ - Device Intelligence SDK integration
8
+ - Auto-configuration via plugin variables
9
+ - TypeScript definitions
package/LICENSE ADDED
@@ -0,0 +1,11 @@
1
+ Apache License 2.0
2
+ Copyright 2026 GatekeeperX
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+ http://www.apache.org/licenses/LICENSE-2.0
7
+ Unless required by applicable law or agreed to in writing, software
8
+ distributed under the License is distributed on an "AS IS" BASIS,
9
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ See the License for the specific language governing permissions and
11
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,484 @@
1
+ # cordova-plugin-devicex
2
+
3
+ [![npm version](https://badge.fury.io/js/cordova-plugin-devicex.svg)](https://www.npmjs.com/package/cordova-plugin-devicex)
4
+ [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
5
+
6
+ Plugin Cordova oficial que expone la potencia del SDK nativo **GatekeeperX Device Intelligence Android**. Actúa como un **Bridge** directo hacia la librería `device-intelligence-android`, exponiendo capacidades de fingerprinting profundo, detección de fraude y telemetría de seguridad en tiempo real.
7
+
8
+ ## 🚀 Features
9
+
10
+ - ✅ **Detección de rooting/jailbreak** (Magisk, Frida, Xposed, Superuser)
11
+ - ✅ **Identificación de emuladores** (AVD, Genymotion, Bluestacks)
12
+ - ✅ **Risk scoring** basado en +50 señales del dispositivo
13
+ - ✅ **Deep Fingerprinting**:
14
+ - 🔋 Batería & Energía
15
+ - 📷 Cámaras & Codecs
16
+ - 💾 CPU, GPU & Memoria
17
+ - 📡 Sensores & Input Devices
18
+ - 📦 Package Manager & Settings
19
+ - ✅ **Event tracking** con telemetría de seguridad automática
20
+ - ✅ **Configuración manual** flexible desde el código
21
+ - ✅ **TypeScript definitions** incluidas
22
+ - ✅ **Integration Bridge**: Mapeo directo 1:1 con `device-intelligence-android`
23
+ - ✅ **Soporte cordova-android >= 11**
24
+
25
+ ---
26
+
27
+ ## 📋 Tabla de Contenidos
28
+
29
+ - [Requisitos](#-requisitos)
30
+ - [Instalación](#-instalación)
31
+ - [Uso](#-uso)
32
+ - [Ejemplos básicos](#ejemplos-básicos)
33
+ - [Casos de uso reales](#casos-de-uso-reales)
34
+ - [API Reference](#-api-reference)
35
+ - [Configuración avanzada](#-configuración-avanzada)
36
+ - [Seguridad y mejores prácticas](#-seguridad-y-mejores-prácticas)
37
+ - [Solución de problemas](#-solución-de-problemas)
38
+ - [Desarrollo y contribución](#-desarrollo-y-contribución)
39
+ - [Licencia](#licencia)
40
+
41
+ ---
42
+
43
+ ## ⚡ Quick Start
44
+
45
+ ```bash
46
+ # 1. Instalar plugin desde npm
47
+ ionic cordova plugin add cordova-plugin-devicex
48
+
49
+ # 2. Agregar plataforma Android 11+
50
+ ionic cordova platform add android@11
51
+
52
+ # 3. Construir
53
+ ionic cordova build android
54
+ ```
55
+
56
+ **Uso en tu app:**
57
+
58
+ ```typescript
59
+ declare const Devicex: any;
60
+
61
+ // El SDK debe ser inicializado manualmente antes de su uso
62
+ await Devicex.configure({
63
+ tenant: 'gatekeeperx',
64
+ apiKey: 'tu-api-key',
65
+ environment: 'SANDBOX'
66
+ });
67
+
68
+ // Enviar eventos con telemetría de seguridad automática
69
+ const result = await Devicex.sendEvent('app_start');
70
+ console.log('Event sent:', result.ok, 'DeviceXId:', result.deviceXId);
71
+ ```
72
+
73
+ ---
74
+
75
+ ## 📦 Requisitos
76
+
77
+ - **Node.js** y npm
78
+ - **Java JDK 11 o 17** (para cordova-android 11+)
79
+ - **Android SDK** instalado y configurado
80
+ - **Ionic CLI** (si usas Ionic)
81
+
82
+ ```bash
83
+ # Configurar Java y Android SDK
84
+ export JAVA_HOME="$(/usr/libexec/java_home -v 17)"
85
+ export ANDROID_SDK_ROOT="$HOME/Library/Android/sdk"
86
+ ```
87
+
88
+ ---
89
+
90
+ ## 🔧 Instalación
91
+
92
+ ### Desde npm (recomendado)
93
+
94
+ ```bash
95
+ ionic cordova plugin add cordova-plugin-devicex
96
+ ```
97
+
98
+ ### Agregar plataforma Android
99
+
100
+ ```bash
101
+ ionic cordova platform add android@11
102
+ # O versión superior (12, 13, etc.)
103
+ ```
104
+
105
+ ### Construir y ejecutar
106
+
107
+ ```bash
108
+ # Build
109
+ ionic cordova build android
110
+
111
+ # Ejecutar en dispositivo
112
+ ionic cordova run android --device
113
+
114
+ # Ejecutar en emulador
115
+ ionic cordova run android --emulator
116
+
117
+ # Ver logs
118
+ adb logcat | grep -i -E "devicex|gatekeeperx"
119
+ ```
120
+
121
+ ---
122
+
123
+ ## 💻 Uso
124
+
125
+ ### Declaración TypeScript
126
+
127
+ ```typescript
128
+ // Declarar el objeto global Devicex
129
+ declare const Devicex: any;
130
+ ```
131
+
132
+ ### Ejemplos básicos
133
+
134
+ #### 1. Verificar inicialización
135
+
136
+ ```typescript
137
+ const initialized = await Devicex.isInitialized();
138
+ console.log('SDK initialized:', initialized);
139
+ ```
140
+
141
+ #### 2. Obtener versión del SDK
142
+
143
+ ```typescript
144
+ const version = await Devicex.getVersion();
145
+ console.log('SDK version:', version);
146
+ ```
147
+
148
+ #### 3. Enviar evento personalizado
149
+
150
+ ```typescript
151
+ const result = await Devicex.sendEvent(
152
+ 'view_product',
153
+ { productId: '12345', category: 'electronics' },
154
+ { 'X-Trace-Id': 'abc-123' }
155
+ );
156
+
157
+ console.log('Event sent:', result.ok);
158
+ console.log('Device ID:', result.deviceXId);
159
+ ```
160
+
161
+ ### Casos de uso reales
162
+
163
+ ### Casos de uso reales
164
+
165
+ #### Login seguro
166
+
167
+ ```typescript
168
+ async function handleLogin(username: string, password: string) {
169
+ // Proceder con login
170
+ const loginResult = await authenticate(username, password);
171
+
172
+ // Enviar evento de login (el SDK adjunta fingerprint y risk signals internamente)
173
+ await Devicex.sendEvent('login', {
174
+ method: 'password',
175
+ success: loginResult.success
176
+ });
177
+ }
178
+ ```
179
+
180
+ #### Monitoreo de pantallas
181
+
182
+ ```typescript
183
+ // En tu componente/página (Ionic)
184
+ async ionViewDidEnter() {
185
+ await Devicex.sendEvent('view_screen', {
186
+ screen: 'home',
187
+ timestamp: Date.now()
188
+ });
189
+ }
190
+ ```
191
+
192
+ ---
193
+
194
+ ## 📚 API Reference
195
+
196
+ Este plugin utiliza `DevicexPlugin.kt` para mapear las llamadas JavaScript directamente a los métodos nativos del SDK:
197
+
198
+ | Método JS | Método Nativo (Kotlin) | Descripción |
199
+ |-----------|------------------------|-------------|
200
+ | `configure()` | `Devicex.configure()` | Inicializa el SDK con tu API Key y Tenant. |
201
+ | `sendEvent()` | `Devicex.sendEvent()` | Envía eventos de negocio asegurados con fingerprinting. |
202
+ | `getVersion()` | `Devicex.getVersion()` | Retorna la versión del SDK nativo subyacente. |
203
+ | `isInitialized()` | `Devicex.isInitialized()` | Verifica si la instancia `agent` está lista. |
204
+
205
+ ### `Devicex.configure(config)`
206
+
207
+
208
+
209
+ Configura el SDK. Este paso es obligatorio antes de realizar cualquier otra llamada.
210
+
211
+ ```typescript
212
+ await Devicex.configure({
213
+ tenant: 'gatekeeperx',
214
+ apiKey: 'your-api-key',
215
+ environment: 'PRODUCTION', // 'DEVELOPMENT' | 'SANDBOX' | 'PRODUCTION'
216
+ organizationId: 'your-org-id',
217
+ headers: { 'X-Custom-Header': 'value' } // opcional
218
+ });
219
+ ```
220
+
221
+ **Parámetros:**
222
+ - `tenant` (string, requerido): Tenant de GatekeeperX
223
+ - `apiKey` (string, requerido): API Key de autenticación
224
+ - `environment` (string, opcional): Entorno del SDK
225
+ - `organizationId` (string, opcional): ID de organización
226
+ - `headers` (object, opcional): Headers HTTP personalizados
227
+
228
+ **Retorna:** `Promise<void>`
229
+
230
+ ---
231
+
232
+ ### `Devicex.isInitialized()`
233
+
234
+ Verifica si el SDK está inicializado y listo para usarse.
235
+
236
+ ```typescript
237
+ const initialized = await Devicex.isInitialized();
238
+ ```
239
+
240
+ **Retorna:** `Promise<boolean>`
241
+
242
+ ---
243
+
244
+ ### `Devicex.getVersion()`
245
+
246
+ Obtiene la versión actual del SDK nativo.
247
+
248
+ ```typescript
249
+ const version = await Devicex.getVersion();
250
+ // Ejemplo: "1.1.6"
251
+ ```
252
+
253
+ **Retorna:** `Promise<string>`
254
+
255
+ ---
256
+
257
+
258
+
259
+ ### `Devicex.sendEvent(eventType, metadata?, headers?)`
260
+
261
+ Envía un evento personalizado al backend de GatekeeperX.
262
+
263
+ ```typescript
264
+ const result = await Devicex.sendEvent(
265
+ 'login',
266
+ { method: 'oauth', provider: 'google' },
267
+ { 'X-Request-ID': 'abc-123' }
268
+ );
269
+ ```
270
+
271
+ **Parámetros:**
272
+ - `eventType` (string, requerido): Tipo de evento (ej: `'login'`, `'checkout'`, `'view_screen'`)
273
+ - `metadata` (object, opcional): Datos adicionales del evento
274
+ - `headers` (object, opcional): Headers HTTP personalizados para esta request
275
+
276
+ **Retorna:** `Promise<EventResult>`
277
+
278
+ ```typescript
279
+ interface EventResult {
280
+ ok: boolean; // true si el evento se envió exitosamente
281
+ code?: string; // Código de respuesta del backend
282
+ deviceXId?: string; // ID del dispositivo
283
+ message?: string; // Mensaje de éxito
284
+ errorCode?: string; // Código de error (si ok=false)
285
+ errorMessage?: string; // Mensaje de error (si ok=false)
286
+ httpCode?: number; // Código HTTP de la respuesta
287
+ }
288
+ ```
289
+
290
+ ---
291
+
292
+ ## ⚙️ Configuración manual
293
+
294
+ Es obligatorio configurar el SDK al inicio de la aplicación:
295
+
296
+ ```typescript
297
+ // En tu app.component.ts o main.ts
298
+ async ngOnInit() {
299
+ if (this.platform.is('cordova')) {
300
+ await (window as any).Devicex.configure({
301
+ tenant: 'gatekeeperx',
302
+ apiKey: 'your-api-key',
303
+ environment: 'PRODUCTION',
304
+ organizationId: 'org123'
305
+ });
306
+ }
307
+ }
308
+ ```
309
+
310
+ ### Guardias de plataforma
311
+
312
+ Siempre verifica que estás en Cordova antes de usar el plugin:
313
+
314
+ ```typescript
315
+ import { Platform } from '@ionic/angular';
316
+
317
+ constructor(private platform: Platform) {}
318
+
319
+ async doSomething() {
320
+ if (this.platform.is('cordova') && (window as any).Devicex) {
321
+ const risk = await (window as any).Devicex.getRiskAssessment();
322
+ }
323
+ }
324
+ ```
325
+
326
+ ---
327
+
328
+ ## 🔒 Seguridad y mejores prácticas
329
+
330
+ ### ✅ DO
331
+
332
+ - **Configura el SDK al inicio** mediante el método `configure`
333
+ - **Protege API keys** en CI/CD con secret managers
334
+ - **Usa `DEVELOPMENT`** para desarrollo/pruebas
335
+ - **Usa `PRODUCTION`** solo en builds release
336
+ - **Verifica `platform.is('cordova')`** antes de usar el plugin
337
+ - **Implementa rate limiting** en eventos personalizados
338
+
339
+ ### ❌ DON'T
340
+
341
+ - ❌ **No hardcodees** API keys en código fuente
342
+ - ❌ **No commitees** credenciales en Git
343
+ - ❌ **No envíes** PII (datos personales) en metadata de eventos
344
+ - ❌ **No uses** el mismo API key para dev y prod
345
+
346
+ ### Ejemplo de integración segura
347
+
348
+ ### Ejemplo de integración segura
349
+
350
+ ```typescript
351
+ async ionViewDidLoad() {
352
+ if (!this.platform.is('cordova')) return;
353
+
354
+ // El SDK adjuntará automáticamente las señales de seguridad
355
+ const result = await (window as any).Devicex.sendEvent('page_view', {
356
+ page: 'home'
357
+ });
358
+
359
+ console.log('Security telemetry sent:', result.ok);
360
+ }
361
+ ```
362
+
363
+ ---
364
+
365
+ ## 🛠 Solución de problemas
366
+
367
+ ### Error: "class not found" o referencias no resueltas
368
+
369
+ **Causa:** AAR no incluidos o Gradle no configurado correctamente.
370
+
371
+ **Solución:**
372
+ ```bash
373
+ # Verifica que existan los AAR
374
+ ls -lh platforms/android/app/libs/devicex*.aar
375
+
376
+ # Re-agregar plugin
377
+ ionic cordova plugin rm cordova-plugin-devicex
378
+ ionic cordova plugin add cordova-plugin-devicex
379
+
380
+ # Limpiar y rebuild
381
+ ionic cordova platform rm android
382
+ ionic cordova platform add android@11
383
+ ionic cordova build android
384
+ ```
385
+
386
+ ---
387
+
388
+ ### Error: Conflictos de dependencias Kotlin
389
+
390
+ **Causa:** Versiones incompatibles de Kotlin en tu proyecto.
391
+
392
+ **Solución:**
393
+
394
+ Este plugin usa:
395
+ - `kotlin-stdlib:1.9.25`
396
+ - `kotlinx-coroutines-android:1.7.3`
397
+
398
+ Asegúrate de no forzar versiones diferentes en tu `build.gradle`.
399
+
400
+ ---
401
+
402
+ ### Warning: "Mutating configuration after resolution"
403
+
404
+ **Causa:** Warning de Gradle 8.x relacionado con el hook de configuración.
405
+
406
+ **Solución:** Este es un aviso no bloqueante. La build funcionará correctamente. Se resolverá en futuras versiones del plugin.
407
+
408
+ ---
409
+
410
+ ### Plugin no disponible en runtime
411
+
412
+ **Causa:** No verificaste que Cordova esté cargado.
413
+
414
+ **Solución:**
415
+ ```typescript
416
+ // Espera a que Cordova esté listo
417
+ this.platform.ready().then(() => {
418
+ if ((window as any).Devicex) {
419
+ // Usa el plugin aquí
420
+ }
421
+ });
422
+ ```
423
+
424
+ ---
425
+
426
+ ## 🏗 Desarrollo y contribución
427
+
428
+ ### Qué incluye este plugin
429
+
430
+ - `src/android/libs/devicex-bridge.aar`: Bridge Kotlin con API Cordova
431
+ - `src/android/libs/devicex-1.1.3.aar`: SDK Device Intelligence empaquetado
432
+ - `www/devicex.js`: Interfaz JavaScript
433
+ - `types/index.d.ts`: Definiciones TypeScript
434
+ - Dependencias: `kotlin-stdlib:1.9.25`, `kotlinx-coroutines-android:1.7.3`
435
+
436
+ ### Reconstruir AARs (solo mantenedores)
437
+
438
+ **Compilar SDK:**
439
+ ```bash
440
+ cd device-intelligence-android
441
+ export JAVA_HOME="$(/usr/libexec/java_home -v 11)"
442
+ ./gradlew :devicex:clean :devicex:assembleProdEnvRelease
443
+ ./gradlew :devicex:publishAgentProductionReleasePublicationToMavenLocal
444
+ ```
445
+
446
+ **Compilar bridge:**
447
+ ```bash
448
+ cd devicex-bridge-android
449
+ export JAVA_HOME="$(/usr/libexec/java_home -v 11)"
450
+ ./gradlew :bridge:clean :bridge:assembleRelease
451
+ ```
452
+
453
+ **Copiar AARs al plugin:**
454
+ ```bash
455
+ cp devicex-bridge-android/bridge/build/outputs/aar/devicex-bridge.aar \
456
+ cordova-plugin-devicex/src/android/libs/
457
+
458
+ cp ~/.m2/repository/com/gatekeeperx/devicex/1.1.6/devicex-1.1.3.aar \
459
+ cordova-plugin-devicex/src/android/libs/
460
+ ```
461
+
462
+ ### Publicar a npm
463
+
464
+ ```bash
465
+ # Actualizar versión
466
+ npm version patch # o minor/major
467
+
468
+ # Publicar
469
+ npm publish --access public
470
+ ```
471
+
472
+ ---
473
+
474
+ ## Licencia
475
+
476
+ Apache-2.0
477
+
478
+ ---
479
+
480
+ ## Soporte
481
+
482
+ - **Documentación:** [https://docs.gatekeeperx.com](https://docs.gatekeeperx.com)
483
+ - **Issues:** [GitHub Issues](https://github.com/gatekeeperx/cordova-plugin-devicex/issues)
484
+ - **npm:** [cordova-plugin-devicex](https://www.npmjs.com/package/cordova-plugin-devicex)
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@gatekeeperx/cordova-plugin-devicex",
3
+ "version": "1.2.5",
4
+ "description": "GatekeeperX Device Intelligence Cordova plugin (Android)",
5
+ "license": "Apache-2.0",
6
+ "keywords": [
7
+ "cordova",
8
+ "cordova-android",
9
+ "gatekeeperx",
10
+ "device",
11
+ "security",
12
+ "intelligence"
13
+ ],
14
+ "engines": [
15
+ {
16
+ "name": "cordova-android",
17
+ "version": ">=11.0.0"
18
+ }
19
+ ],
20
+ "cordova": {
21
+ "id": "cordova-plugin-devicex",
22
+ "platforms": [
23
+ "android"
24
+ ]
25
+ },
26
+ "main": "www/devicex.js",
27
+ "types": "types/index.d.ts",
28
+ "files": [
29
+ "plugin.xml",
30
+ "www/",
31
+ "types/",
32
+ "src/android/",
33
+ "README.md",
34
+ "CHANGELOG.md",
35
+ "LICENSE"
36
+ ],
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "git+https://github.com/gatekeeperx/deviceX-plugins.git"
40
+ },
41
+ "author": "GatekeeperX",
42
+ "bugs": {
43
+ "url": "https://github.com/gatekeeperx/deviceX-plugins/issues"
44
+ },
45
+ "homepage": "https://github.com/gatekeeperx/deviceX-plugins/tree/master/cordova/cordova-plugin-devicex"
46
+ }
package/plugin.xml ADDED
@@ -0,0 +1,50 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <plugin id="@gatekeeperx/cordova-plugin-devicex"
3
+ xmlns="http://apache.org/cordova/ns/plugins/1.0"
4
+ xmlns:android="http://schemas.android.com/apk/res/android" version="1.2.1">
5
+ <name>Devicex</name>
6
+ <description>GatekeeperX Device Intelligence Cordova plugin (Android)</description>
7
+ <license>Apache-2.0</license>
8
+ <keywords>cordova, gatekeeperx, device, intelligence, security</keywords>
9
+
10
+ <js-module name="Devicex" src="www/devicex.js">
11
+ <clobbers target="DeviceX" />
12
+ </js-module>
13
+
14
+ <engines>
15
+ <engine name="cordova-android" version=">=11.0.0" />
16
+ </engines>
17
+
18
+ <platform name="android">
19
+ <!-- Runtime dependencies -->
20
+ <!-- Kotlin stdlib alineado con el bridge -->
21
+ <framework src="org.jetbrains.kotlin:kotlin-stdlib:1.9.25" />
22
+ <framework src="org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3" />
23
+
24
+ <!-- Kotlinx Serialization (requerido por Ktor) -->
25
+ <framework src="org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2" />
26
+
27
+ <!-- Ktor Client (HTTP engine del SDK) -->
28
+ <framework src="io.ktor:ktor-client-cio:2.3.7" />
29
+ <framework src="io.ktor:ktor-client-logging:2.3.7" />
30
+ <framework src="io.ktor:ktor-client-content-negotiation:2.3.7" />
31
+ <framework src="io.ktor:ktor-serialization-kotlinx-json:2.3.7" />
32
+ <!-- AARs locales -->
33
+ <lib-file src="src/android/libs/devicex-bridge.aar" arch="device" />
34
+ <lib-file src="src/android/libs/devicex-1.2.5.aar" arch="device" />
35
+
36
+ <!-- Hook para configurar Gradle -->
37
+ <hook type="after_plugin_install" src="src/android/hooks/configure-gradle.js" />
38
+
39
+ <!-- Registrar el plugin nativo en config.xml -->
40
+ <config-file target="res/xml/config.xml" parent="/*">
41
+ <feature name="Devicex">
42
+ <param name="android-package" value="com.gatekeeperx.cordova.DevicexPlugin" />
43
+ <param name="onload" value="true" />
44
+ </feature>
45
+ </config-file>
46
+
47
+ <!-- Incluir la clase Java del plugin -->
48
+ <source-file src="src/android/com/gatekeeperx/cordova/DevicexPlugin.java" target-dir="src/com/gatekeeperx/cordova" />
49
+ </platform>
50
+ </plugin>
@@ -0,0 +1,204 @@
1
+ package com.gatekeeperx.cordova;
2
+
3
+ import android.content.Context;
4
+
5
+ import org.apache.cordova.CallbackContext;
6
+ import org.apache.cordova.CordovaInterface;
7
+ import org.apache.cordova.CordovaPlugin;
8
+ import org.apache.cordova.CordovaWebView;
9
+ import org.json.JSONArray;
10
+ import org.json.JSONException;
11
+ import org.json.JSONObject;
12
+
13
+ import java.util.ArrayList;
14
+ import java.util.HashMap;
15
+ import java.util.Iterator;
16
+ import java.util.List;
17
+ import java.util.Map;
18
+
19
+ public class DevicexPlugin extends CordovaPlugin {
20
+
21
+ @Override
22
+ public void initialize(CordovaInterface cordova, CordovaWebView webView) {
23
+ super.initialize(cordova, webView);
24
+ try {
25
+ Context ctx = cordova.getActivity().getApplicationContext();
26
+ android.util.Log.d("DevicexPlugin", "Reading meta-data from manifest...");
27
+
28
+ android.content.pm.ApplicationInfo ai = ctx.getPackageManager()
29
+ .getApplicationInfo(ctx.getPackageName(), android.content.pm.PackageManager.GET_META_DATA);
30
+ android.os.Bundle meta = ai.metaData;
31
+
32
+ if (meta == null) {
33
+ android.util.Log.e("DevicexPlugin", "No meta-data found in manifest");
34
+ return;
35
+ }
36
+
37
+ String tenant = meta.getString("com.gatekeeperx.deviceintelligence.TENANT");
38
+ String apiKey = meta.getString("com.gatekeeperx.deviceintelligence.API_KEY");
39
+ String env = meta.getString("com.gatekeeperx.deviceintelligence.ENVIRONMENT");
40
+ String orgId = meta.getString("com.gatekeeperx.deviceintelligence.ORGANIZATION_ID");
41
+
42
+ android.util.Log.d("DevicexPlugin", "Tenant: " + tenant + ", Env: " + env);
43
+
44
+ if (tenant == null || tenant.trim().isEmpty() || apiKey == null || apiKey.trim().isEmpty()) {
45
+ android.util.Log.d("DevicexPlugin", "Auto-config skipped: no credentials provided");
46
+ return;
47
+ }
48
+
49
+ boolean ok = DevicexBridge.INSTANCE.configure(
50
+ ctx,
51
+ tenant.trim(),
52
+ apiKey.trim(),
53
+ env != null ? env.trim() : "PRODUCTION",
54
+ orgId != null ? orgId.trim() : null,
55
+ null);
56
+
57
+ android.util.Log.d("DevicexPlugin", "Manual configure result: " + ok);
58
+ } catch (Throwable e) {
59
+ android.util.Log.e("DevicexPlugin", "Error initializing: " + e.getMessage(), e);
60
+ }
61
+ }
62
+
63
+ @Override
64
+ public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
65
+ switch (action) {
66
+ case "configure":
67
+ configure(args, callbackContext);
68
+ return true;
69
+ case "sendEvent":
70
+ sendEvent(args, callbackContext);
71
+ return true;
72
+ case "isInitialized":
73
+ try {
74
+ boolean value = DevicexBridge.INSTANCE.isInitialized();
75
+ callbackContext.success(new JSONObject().put("value", value));
76
+ } catch (JSONException e) {
77
+ callbackContext.error(e.getMessage());
78
+ }
79
+ return true;
80
+ case "getVersion":
81
+ try {
82
+ String value = DevicexBridge.INSTANCE.getVersion();
83
+ callbackContext.success(new JSONObject().put("value", value));
84
+ } catch (JSONException e) {
85
+ callbackContext.error(e.getMessage());
86
+ }
87
+ return true;
88
+ default:
89
+ return false;
90
+ }
91
+ }
92
+
93
+ private void configure(JSONArray args, CallbackContext cb) {
94
+ try {
95
+ JSONObject obj = args.optJSONObject(0);
96
+ if (obj == null)
97
+ obj = new JSONObject();
98
+ Context ctx = cordova.getActivity().getApplicationContext();
99
+ String tenant = obj.optString("tenant", "").trim();
100
+ String apiKey = obj.optString("apiKey", "").trim();
101
+ String orgId = obj.optString("organizationId", "").trim();
102
+ String env = obj.optString("environment", "PRODUCTION").trim();
103
+ JSONObject headersObj = obj.optJSONObject("headers");
104
+ Map<String, String> headers = headersObj != null ? toStringMap(headersObj) : new HashMap<>();
105
+
106
+ if (tenant.isEmpty() || apiKey.isEmpty()) {
107
+ cb.error("tenant and apiKey are required");
108
+ return;
109
+ }
110
+
111
+ boolean ok = DevicexBridge.INSTANCE.configure(
112
+ ctx,
113
+ tenant,
114
+ apiKey,
115
+ env,
116
+ orgId.isEmpty() ? null : orgId,
117
+ headers);
118
+ if (ok)
119
+ cb.success();
120
+ else
121
+ cb.error("configure failed");
122
+ } catch (Throwable e) {
123
+ cb.error(e.getMessage());
124
+ }
125
+ }
126
+
127
+ private void sendEvent(JSONArray args, final CallbackContext cb) {
128
+ try {
129
+ JSONObject obj = args.optJSONObject(0);
130
+ if (obj == null)
131
+ obj = new JSONObject();
132
+ String name = obj.optString("name", "").trim();
133
+ if (name.isEmpty()) {
134
+ cb.error("name is required");
135
+ return;
136
+ }
137
+ JSONObject propsObj = obj.optJSONObject("properties");
138
+ JSONObject headersObj = obj.optJSONObject("headers");
139
+ Map<String, Object> properties = propsObj != null ? toAnyMap(propsObj) : new HashMap<String, Object>();
140
+ Map<String, String> headers = headersObj != null ? toStringMap(headersObj) : new HashMap<String, String>();
141
+
142
+ @SuppressWarnings("unchecked")
143
+ DevicexBridge.EventCallback callback = new DevicexBridge.EventCallback() {
144
+ @Override
145
+ public void onResult(Map result) {
146
+ try {
147
+ cb.success(new JSONObject(result));
148
+ } catch (Throwable t) {
149
+ cb.error(t.getMessage());
150
+ }
151
+ }
152
+ };
153
+ DevicexBridge.INSTANCE.sendEvent(name, properties, headers, callback);
154
+ } catch (Throwable e) {
155
+ cb.error(e.getMessage());
156
+ }
157
+ }
158
+
159
+ // Helpers
160
+ private static Map<String, String> toStringMap(JSONObject obj) {
161
+ Map<String, String> map = new HashMap<>();
162
+ Iterator<String> it = obj.keys();
163
+ while (it.hasNext()) {
164
+ String k = it.next();
165
+ String v = obj.optString(k, null);
166
+ if (v != null)
167
+ map.put(k, v);
168
+ }
169
+ return map;
170
+ }
171
+
172
+ private static Map<String, Object> toAnyMap(JSONObject obj) {
173
+ Map<String, Object> map = new HashMap<>();
174
+ Iterator<String> it = obj.keys();
175
+ while (it.hasNext()) {
176
+ String k = it.next();
177
+ Object v = obj.opt(k);
178
+ map.put(k, fromJson(v));
179
+ }
180
+ return map;
181
+ }
182
+
183
+ private static Object fromJson(Object v) {
184
+ if (v == null || v == JSONObject.NULL)
185
+ return null;
186
+ if (v instanceof JSONObject)
187
+ return toAnyMap((JSONObject) v);
188
+ if (v instanceof JSONArray)
189
+ return toList((JSONArray) v);
190
+ if (v instanceof String || v instanceof Boolean || v instanceof Integer || v instanceof Long
191
+ || v instanceof Double)
192
+ return v;
193
+ return String.valueOf(v);
194
+ }
195
+
196
+ private static List<Object> toList(JSONArray arr) {
197
+ List<Object> list = new ArrayList<>();
198
+ for (int i = 0; i < arr.length(); i++) {
199
+ Object v = arr.opt(i);
200
+ list.add(fromJson(v));
201
+ }
202
+ return list;
203
+ }
204
+ }
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+
6
+ module.exports = function (context) {
7
+ const platforms = context.opts.cordova.platforms;
8
+ if (platforms.indexOf('android') === -1) return;
9
+
10
+ const buildGradlePath = path.join(
11
+ context.opts.projectRoot,
12
+ 'platforms',
13
+ 'android',
14
+ 'app',
15
+ 'build.gradle'
16
+ );
17
+
18
+ if (!fs.existsSync(buildGradlePath)) {
19
+ console.log('[devicex] build.gradle no encontrado');
20
+ return;
21
+ }
22
+
23
+ let buildGradle = fs.readFileSync(buildGradlePath, 'utf8');
24
+
25
+ // Agregar repositorio flatDir si no existe en el bloque principal
26
+ if (buildGradle.indexOf('flatDir') === -1) {
27
+ const repoBlock = `
28
+ repositories {
29
+ flatDir {
30
+ dirs 'libs'
31
+ }
32
+ }
33
+ `;
34
+ // Insertar antes del último bloque dependencies (el principal)
35
+ const lastDepsIndex = buildGradle.lastIndexOf('dependencies {');
36
+ if (lastDepsIndex !== -1) {
37
+ buildGradle = buildGradle.slice(0, lastDepsIndex) +
38
+ repoBlock + '\n' +
39
+ buildGradle.slice(lastDepsIndex);
40
+ }
41
+ }
42
+
43
+ // Agregar dependencias de AARs después de fileTree si no existen
44
+ if (buildGradle.indexOf('devicex-bridge') === -1) {
45
+ const depsBlock = ` implementation files('libs/devicex-bridge.aar')
46
+ implementation files('libs/devicex-1.2.5.aar')
47
+
48
+ // Dependencias del SDK Devicex
49
+ implementation 'io.ktor:ktor-client-core:2.3.7'
50
+ implementation 'io.ktor:ktor-client-okhttp:2.3.7'
51
+ implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.2'
52
+ `;
53
+ // Buscar después de fileTree en el bloque principal
54
+ buildGradle = buildGradle.replace(
55
+ /(implementation fileTree\(dir: 'libs', include: '\*\.jar'\))/,
56
+ '$1\n' + depsBlock
57
+ );
58
+ }
59
+
60
+ fs.writeFileSync(buildGradlePath, buildGradle, 'utf8');
61
+ console.log('[devicex] build.gradle configurado con AARs locales');
62
+ };
@@ -0,0 +1,52 @@
1
+ // Type definitions for cordova-plugin-devicex
2
+ // Project: https://npmjs.com/package/cordova-plugin-devicex
3
+ // Definitions by: GatekeeperX
4
+
5
+ export type Environment = 'DEV' | 'DEVELOPMENT' | 'SANDBOX' | 'STAGE' | 'STAGING' | 'PROD' | 'PRODUCTION';
6
+
7
+ export interface ConfigureOptions {
8
+ tenant: string;
9
+ apiKey: string;
10
+ organizationId?: string;
11
+ environment?: Environment;
12
+ headers?: Record<string, string>;
13
+ }
14
+
15
+ export interface EventSuccess {
16
+ ok: true;
17
+ code: number;
18
+ deviceXId: string;
19
+ message?: string;
20
+ }
21
+
22
+ export interface EventFailure {
23
+ ok: false;
24
+ errorCode: string;
25
+ errorMessage: string;
26
+ httpCode?: number | null;
27
+ }
28
+
29
+ export type EventResult = EventSuccess | EventFailure;
30
+
31
+ export interface RiskAssessment {
32
+ isRooted: boolean;
33
+ isFridaDetected: boolean;
34
+ isXposedDetected: boolean;
35
+ isMagiskDetected: boolean;
36
+ isEmulator: boolean;
37
+ isDebuggerAttached: boolean;
38
+ isHookingDetected: boolean;
39
+ riskScore: number;
40
+ riskLevel: string;
41
+ }
42
+
43
+ declare const Devicex: {
44
+ configure(options: ConfigureOptions): Promise<void>;
45
+ sendEvent(name: string, properties?: Record<string, any>, headers?: Record<string, string>): Promise<EventResult>;
46
+ getRiskAssessment(): Promise<RiskAssessment>;
47
+ isInitialized(): Promise<boolean>;
48
+ getVersion(): Promise<string>;
49
+ };
50
+
51
+ export default Devicex;
52
+ export as namespace Devicex;
package/www/devicex.js ADDED
@@ -0,0 +1,28 @@
1
+ var exec = require('cordova/exec');
2
+ var PLUGIN = 'Devicex';
3
+
4
+ function call(action, args) {
5
+ return new Promise(function (resolve, reject) {
6
+ exec(function (res) { resolve(res); }, function (err) { reject(err); }, PLUGIN, action, args || []);
7
+ });
8
+ }
9
+
10
+ exports.configure = function (options) {
11
+ options = options || {};
12
+ return call('configure', [options]);
13
+ };
14
+
15
+ exports.sendEvent = function (name, properties, headers) {
16
+ if (!name || typeof name !== 'string') {
17
+ return Promise.reject('name is required');
18
+ }
19
+ return call('sendEvent', [{ name: name, properties: properties || {}, headers: headers || {} }]);
20
+ };
21
+
22
+ exports.isInitialized = function () {
23
+ return call('isInitialized', []).then(function (res) { return res && res.value === true; });
24
+ };
25
+
26
+ exports.getVersion = function () {
27
+ return call('getVersion', []).then(function (res) { return (res && res.value) || ''; });
28
+ };