@capgo/capacitor-device-integrity 8.0.2

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.
@@ -0,0 +1,3 @@
1
+ /// <reference types="@capacitor/cli" />
2
+ export {};
3
+ //# sourceMappingURL=definitions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAAA,wCAAwC","sourcesContent":["/// <reference types=\"@capacitor/cli\" />\n\ndeclare module '@capacitor/cli' {\n export interface PluginsConfig {\n /**\n * Device Integrity plugin configuration.\n */\n DeviceIntegrity?: DeviceIntegrityPluginConfig;\n }\n}\n\n/**\n * Capacitor config for the Device Integrity plugin.\n */\nexport interface DeviceIntegrityPluginConfig {\n /**\n * Android only. Google Cloud project number used by the Play Integrity Standard API.\n *\n * Example:\n * `plugins.DeviceIntegrity.cloudProjectNumber = '123456789012'`\n */\n cloudProjectNumber?: string;\n}\n\nexport type DeviceIntegrityPlatform = 'android' | 'ios' | 'web';\n\nexport type AttestationFormat = 'apple-app-attest' | 'google-play-integrity-standard';\n\nexport interface DeviceIntegrityPlugin {\n /**\n * Returns the native integrity capabilities available on the current platform.\n */\n getCapabilities(): Promise<DeviceIntegrityCapabilities>;\n\n /**\n * Returns an Android Widevine-derived fingerprint.\n *\n * The default `fingerprint` is SHA-256 over the Widevine device unique ID and a salt.\n * If `hashSalt` is not provided, Android uses the app package name as the salt.\n *\n * The raw Widevine ID is sensitive and is only returned as base64 when `includeRawId` is true.\n */\n getWidevineFingerprint(options?: WidevineFingerprintOptions): Promise<WidevineFingerprintResult>;\n\n /**\n * Prepares native attestation state and returns the key/provider handle.\n *\n * iOS: creates an App Attest key.\n * Android: prepares a Play Integrity Standard token provider.\n */\n prepareAttestation(options?: PrepareAttestationOptions): Promise<PrepareAttestationResult>;\n\n /**\n * Creates a registration attestation token bound to a backend-issued challenge.\n */\n createAttestation(options: CreateAttestationOptions): Promise<AttestationTokenResult>;\n\n /**\n * Creates a request assertion token bound to a request payload.\n */\n createAssertion(options: CreateAssertionOptions): Promise<AttestationTokenResult>;\n\n /**\n * Creates an iOS DeviceCheck token for server-side fraud-state lookups.\n */\n getDeviceCheckToken(): Promise<DeviceCheckTokenResult>;\n}\n\nexport interface DeviceIntegrityCapabilities {\n /**\n * Platform currently executing the plugin.\n */\n platform: DeviceIntegrityPlatform;\n\n /**\n * Android Widevine DRM support.\n */\n widevine: WidevineCapabilities;\n\n /**\n * iOS App Attest support.\n */\n appAttest: SupportStatus;\n\n /**\n * iOS DeviceCheck support.\n */\n deviceCheck: SupportStatus;\n\n /**\n * Android Play Integrity support.\n */\n playIntegrity: SupportStatus;\n}\n\nexport interface WidevineCapabilities {\n /**\n * Whether the Widevine DRM scheme is supported by the device.\n */\n supported: boolean;\n\n /**\n * Whether the Widevine device unique ID can be read.\n */\n fingerprintAvailable: boolean;\n\n /**\n * Whether the Widevine security level property can be read.\n */\n securityLevelScanSupported: boolean;\n}\n\nexport interface SupportStatus {\n /**\n * Whether the capability is available on the current device.\n */\n supported: boolean;\n}\n\nexport interface WidevineFingerprintOptions {\n /**\n * Return the raw Widevine device unique ID as base64.\n *\n * Defaults to `false`.\n */\n includeRawId?: boolean;\n\n /**\n * Optional salt used to derive `fingerprint`.\n *\n * Android uses the app package name when omitted.\n */\n hashSalt?: string;\n}\n\nexport interface WidevineFingerprintResult {\n /**\n * Always `android`.\n */\n platform: 'android';\n\n /**\n * Always `widevine`.\n */\n source: 'widevine';\n\n /**\n * Salted SHA-256 fingerprint for storing alongside a user record.\n */\n fingerprint: string;\n\n /**\n * Unsalted SHA-256 hash of the Widevine device unique ID.\n */\n widevineIdSha256: string;\n\n /**\n * Raw Widevine device unique ID encoded as base64.\n *\n * Returned only when `includeRawId` is true.\n */\n widevineIdBase64?: string;\n\n /**\n * Widevine security level when available, for example `L1` or `L3`.\n */\n securityLevel?: string;\n\n /**\n * DRM vendor when available.\n */\n vendor?: string;\n\n /**\n * DRM plugin version when available.\n */\n version?: string;\n\n /**\n * DRM plugin description when available.\n */\n description?: string;\n}\n\nexport interface PrepareAttestationOptions {\n /**\n * Android only. Google Cloud project number for Play Integrity.\n *\n * Can be configured globally via `plugins.DeviceIntegrity.cloudProjectNumber`.\n */\n cloudProjectNumber?: string;\n}\n\nexport interface PrepareAttestationResult {\n /**\n * iOS App Attest key ID or Android Play Integrity provider handle ID.\n */\n keyId: string;\n\n /**\n * Native attestation format used by the current platform.\n */\n format: AttestationFormat;\n}\n\nexport interface CreateAttestationOptions {\n /**\n * Key/provider handle returned from `prepareAttestation()`.\n */\n keyId: string;\n\n /**\n * Backend-issued one-time challenge.\n */\n challenge: string;\n\n /**\n * Android only. Google Cloud project number for Play Integrity.\n */\n cloudProjectNumber?: string;\n}\n\nexport interface CreateAssertionOptions {\n /**\n * Key/provider handle returned from `prepareAttestation()`.\n */\n keyId: string;\n\n /**\n * Backend-issued one-time request payload or nonce.\n */\n payload: string;\n\n /**\n * Android only. Google Cloud project number for Play Integrity.\n */\n cloudProjectNumber?: string;\n}\n\nexport interface AttestationTokenResult {\n /**\n * Token/assertion that must be verified server-side.\n */\n token: string;\n\n /**\n * Key/provider handle used to create the token.\n */\n keyId: string;\n\n /**\n * Native attestation format used by the current platform.\n */\n format: AttestationFormat;\n}\n\nexport interface DeviceCheckTokenResult {\n /**\n * iOS DeviceCheck token encoded as base64.\n */\n token: string;\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { DeviceIntegrityPlugin } from './definitions';
2
+ declare const DeviceIntegrity: DeviceIntegrityPlugin;
3
+ export * from './definitions';
4
+ export { DeviceIntegrity };
@@ -0,0 +1,7 @@
1
+ import { registerPlugin } from '@capacitor/core';
2
+ const DeviceIntegrity = registerPlugin('DeviceIntegrity', {
3
+ web: () => import('./web').then((m) => new m.DeviceIntegrityWeb()),
4
+ });
5
+ export * from './definitions';
6
+ export { DeviceIntegrity };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,eAAe,GAAG,cAAc,CAAwB,iBAAiB,EAAE;IAC/E,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,kBAAkB,EAAE,CAAC;CACnE,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,eAAe,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { DeviceIntegrityPlugin } from './definitions';\n\nconst DeviceIntegrity = registerPlugin<DeviceIntegrityPlugin>('DeviceIntegrity', {\n web: () => import('./web').then((m) => new m.DeviceIntegrityWeb()),\n});\n\nexport * from './definitions';\nexport { DeviceIntegrity };\n"]}
@@ -0,0 +1,10 @@
1
+ import { WebPlugin } from '@capacitor/core';
2
+ import type { AttestationTokenResult, CreateAssertionOptions, CreateAttestationOptions, DeviceCheckTokenResult, DeviceIntegrityCapabilities, DeviceIntegrityPlugin, PrepareAttestationOptions, PrepareAttestationResult, WidevineFingerprintOptions, WidevineFingerprintResult } from './definitions';
3
+ export declare class DeviceIntegrityWeb extends WebPlugin implements DeviceIntegrityPlugin {
4
+ getCapabilities(): Promise<DeviceIntegrityCapabilities>;
5
+ getWidevineFingerprint(_options?: WidevineFingerprintOptions): Promise<WidevineFingerprintResult>;
6
+ prepareAttestation(_options?: PrepareAttestationOptions): Promise<PrepareAttestationResult>;
7
+ createAttestation(_options: CreateAttestationOptions): Promise<AttestationTokenResult>;
8
+ createAssertion(_options: CreateAssertionOptions): Promise<AttestationTokenResult>;
9
+ getDeviceCheckToken(): Promise<DeviceCheckTokenResult>;
10
+ }
@@ -0,0 +1,37 @@
1
+ import { WebPlugin } from '@capacitor/core';
2
+ const WEB_ERROR_MESSAGE = 'Device integrity is not available on web. Use the native Android or iOS implementation.';
3
+ export class DeviceIntegrityWeb extends WebPlugin {
4
+ async getCapabilities() {
5
+ return {
6
+ platform: 'web',
7
+ widevine: {
8
+ supported: false,
9
+ fingerprintAvailable: false,
10
+ securityLevelScanSupported: false,
11
+ },
12
+ appAttest: { supported: false },
13
+ deviceCheck: { supported: false },
14
+ playIntegrity: { supported: false },
15
+ };
16
+ }
17
+ async getWidevineFingerprint(_options) {
18
+ void _options;
19
+ throw new Error(WEB_ERROR_MESSAGE);
20
+ }
21
+ async prepareAttestation(_options) {
22
+ void _options;
23
+ throw new Error(WEB_ERROR_MESSAGE);
24
+ }
25
+ async createAttestation(_options) {
26
+ void _options;
27
+ throw new Error(WEB_ERROR_MESSAGE);
28
+ }
29
+ async createAssertion(_options) {
30
+ void _options;
31
+ throw new Error(WEB_ERROR_MESSAGE);
32
+ }
33
+ async getDeviceCheckToken() {
34
+ throw new Error(WEB_ERROR_MESSAGE);
35
+ }
36
+ }
37
+ //# sourceMappingURL=web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAe5C,MAAM,iBAAiB,GAAG,yFAAyF,CAAC;AAEpH,MAAM,OAAO,kBAAmB,SAAQ,SAAS;IAC/C,KAAK,CAAC,eAAe;QACnB,OAAO;YACL,QAAQ,EAAE,KAAK;YACf,QAAQ,EAAE;gBACR,SAAS,EAAE,KAAK;gBAChB,oBAAoB,EAAE,KAAK;gBAC3B,0BAA0B,EAAE,KAAK;aAClC;YACD,SAAS,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE;YAC/B,WAAW,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE;YACjC,aAAa,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE;SACpC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,sBAAsB,CAAC,QAAqC;QAChE,KAAK,QAAQ,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,QAAoC;QAC3D,KAAK,QAAQ,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,QAAkC;QACxD,KAAK,QAAQ,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,QAAgC;QACpD,KAAK,QAAQ,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,mBAAmB;QACvB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACrC,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type {\n AttestationTokenResult,\n CreateAssertionOptions,\n CreateAttestationOptions,\n DeviceCheckTokenResult,\n DeviceIntegrityCapabilities,\n DeviceIntegrityPlugin,\n PrepareAttestationOptions,\n PrepareAttestationResult,\n WidevineFingerprintOptions,\n WidevineFingerprintResult,\n} from './definitions';\n\nconst WEB_ERROR_MESSAGE = 'Device integrity is not available on web. Use the native Android or iOS implementation.';\n\nexport class DeviceIntegrityWeb extends WebPlugin implements DeviceIntegrityPlugin {\n async getCapabilities(): Promise<DeviceIntegrityCapabilities> {\n return {\n platform: 'web',\n widevine: {\n supported: false,\n fingerprintAvailable: false,\n securityLevelScanSupported: false,\n },\n appAttest: { supported: false },\n deviceCheck: { supported: false },\n playIntegrity: { supported: false },\n };\n }\n\n async getWidevineFingerprint(_options?: WidevineFingerprintOptions): Promise<WidevineFingerprintResult> {\n void _options;\n throw new Error(WEB_ERROR_MESSAGE);\n }\n\n async prepareAttestation(_options?: PrepareAttestationOptions): Promise<PrepareAttestationResult> {\n void _options;\n throw new Error(WEB_ERROR_MESSAGE);\n }\n\n async createAttestation(_options: CreateAttestationOptions): Promise<AttestationTokenResult> {\n void _options;\n throw new Error(WEB_ERROR_MESSAGE);\n }\n\n async createAssertion(_options: CreateAssertionOptions): Promise<AttestationTokenResult> {\n void _options;\n throw new Error(WEB_ERROR_MESSAGE);\n }\n\n async getDeviceCheckToken(): Promise<DeviceCheckTokenResult> {\n throw new Error(WEB_ERROR_MESSAGE);\n }\n}\n"]}
@@ -0,0 +1,47 @@
1
+ 'use strict';
2
+
3
+ var core = require('@capacitor/core');
4
+
5
+ const DeviceIntegrity = core.registerPlugin('DeviceIntegrity', {
6
+ web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.DeviceIntegrityWeb()),
7
+ });
8
+
9
+ const WEB_ERROR_MESSAGE = 'Device integrity is not available on web. Use the native Android or iOS implementation.';
10
+ class DeviceIntegrityWeb extends core.WebPlugin {
11
+ async getCapabilities() {
12
+ return {
13
+ platform: 'web',
14
+ widevine: {
15
+ supported: false,
16
+ fingerprintAvailable: false,
17
+ securityLevelScanSupported: false,
18
+ },
19
+ appAttest: { supported: false },
20
+ deviceCheck: { supported: false },
21
+ playIntegrity: { supported: false },
22
+ };
23
+ }
24
+ async getWidevineFingerprint(_options) {
25
+ throw new Error(WEB_ERROR_MESSAGE);
26
+ }
27
+ async prepareAttestation(_options) {
28
+ throw new Error(WEB_ERROR_MESSAGE);
29
+ }
30
+ async createAttestation(_options) {
31
+ throw new Error(WEB_ERROR_MESSAGE);
32
+ }
33
+ async createAssertion(_options) {
34
+ throw new Error(WEB_ERROR_MESSAGE);
35
+ }
36
+ async getDeviceCheckToken() {
37
+ throw new Error(WEB_ERROR_MESSAGE);
38
+ }
39
+ }
40
+
41
+ var web = /*#__PURE__*/Object.freeze({
42
+ __proto__: null,
43
+ DeviceIntegrityWeb: DeviceIntegrityWeb
44
+ });
45
+
46
+ exports.DeviceIntegrity = DeviceIntegrity;
47
+ //# sourceMappingURL=plugin.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst DeviceIntegrity = registerPlugin('DeviceIntegrity', {\n web: () => import('./web').then((m) => new m.DeviceIntegrityWeb()),\n});\nexport * from './definitions';\nexport { DeviceIntegrity };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nconst WEB_ERROR_MESSAGE = 'Device integrity is not available on web. Use the native Android or iOS implementation.';\nexport class DeviceIntegrityWeb extends WebPlugin {\n async getCapabilities() {\n return {\n platform: 'web',\n widevine: {\n supported: false,\n fingerprintAvailable: false,\n securityLevelScanSupported: false,\n },\n appAttest: { supported: false },\n deviceCheck: { supported: false },\n playIntegrity: { supported: false },\n };\n }\n async getWidevineFingerprint(_options) {\n void _options;\n throw new Error(WEB_ERROR_MESSAGE);\n }\n async prepareAttestation(_options) {\n void _options;\n throw new Error(WEB_ERROR_MESSAGE);\n }\n async createAttestation(_options) {\n void _options;\n throw new Error(WEB_ERROR_MESSAGE);\n }\n async createAssertion(_options) {\n void _options;\n throw new Error(WEB_ERROR_MESSAGE);\n }\n async getDeviceCheckToken() {\n throw new Error(WEB_ERROR_MESSAGE);\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,eAAe,GAAGA,mBAAc,CAAC,iBAAiB,EAAE;AAC1D,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,kBAAkB,EAAE,CAAC;AACtE,CAAC;;ACFD,MAAM,iBAAiB,GAAG,yFAAyF;AAC5G,MAAM,kBAAkB,SAASC,cAAS,CAAC;AAClD,IAAI,MAAM,eAAe,GAAG;AAC5B,QAAQ,OAAO;AACf,YAAY,QAAQ,EAAE,KAAK;AAC3B,YAAY,QAAQ,EAAE;AACtB,gBAAgB,SAAS,EAAE,KAAK;AAChC,gBAAgB,oBAAoB,EAAE,KAAK;AAC3C,gBAAgB,0BAA0B,EAAE,KAAK;AACjD,aAAa;AACb,YAAY,SAAS,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE;AAC3C,YAAY,WAAW,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE;AAC7C,YAAY,aAAa,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE;AAC/C,SAAS;AACT,IAAI;AACJ,IAAI,MAAM,sBAAsB,CAAC,QAAQ,EAAE;AAE3C,QAAQ,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC;AAC1C,IAAI;AACJ,IAAI,MAAM,kBAAkB,CAAC,QAAQ,EAAE;AAEvC,QAAQ,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC;AAC1C,IAAI;AACJ,IAAI,MAAM,iBAAiB,CAAC,QAAQ,EAAE;AAEtC,QAAQ,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC;AAC1C,IAAI;AACJ,IAAI,MAAM,eAAe,CAAC,QAAQ,EAAE;AAEpC,QAAQ,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC;AAC1C,IAAI;AACJ,IAAI,MAAM,mBAAmB,GAAG;AAChC,QAAQ,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC;AAC1C,IAAI;AACJ;;;;;;;;;"}
package/dist/plugin.js ADDED
@@ -0,0 +1,50 @@
1
+ var capacitorDeviceIntegrity = (function (exports, core) {
2
+ 'use strict';
3
+
4
+ const DeviceIntegrity = core.registerPlugin('DeviceIntegrity', {
5
+ web: () => Promise.resolve().then(function () { return web; }).then((m) => new m.DeviceIntegrityWeb()),
6
+ });
7
+
8
+ const WEB_ERROR_MESSAGE = 'Device integrity is not available on web. Use the native Android or iOS implementation.';
9
+ class DeviceIntegrityWeb extends core.WebPlugin {
10
+ async getCapabilities() {
11
+ return {
12
+ platform: 'web',
13
+ widevine: {
14
+ supported: false,
15
+ fingerprintAvailable: false,
16
+ securityLevelScanSupported: false,
17
+ },
18
+ appAttest: { supported: false },
19
+ deviceCheck: { supported: false },
20
+ playIntegrity: { supported: false },
21
+ };
22
+ }
23
+ async getWidevineFingerprint(_options) {
24
+ throw new Error(WEB_ERROR_MESSAGE);
25
+ }
26
+ async prepareAttestation(_options) {
27
+ throw new Error(WEB_ERROR_MESSAGE);
28
+ }
29
+ async createAttestation(_options) {
30
+ throw new Error(WEB_ERROR_MESSAGE);
31
+ }
32
+ async createAssertion(_options) {
33
+ throw new Error(WEB_ERROR_MESSAGE);
34
+ }
35
+ async getDeviceCheckToken() {
36
+ throw new Error(WEB_ERROR_MESSAGE);
37
+ }
38
+ }
39
+
40
+ var web = /*#__PURE__*/Object.freeze({
41
+ __proto__: null,
42
+ DeviceIntegrityWeb: DeviceIntegrityWeb
43
+ });
44
+
45
+ exports.DeviceIntegrity = DeviceIntegrity;
46
+
47
+ return exports;
48
+
49
+ })({}, capacitorExports);
50
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst DeviceIntegrity = registerPlugin('DeviceIntegrity', {\n web: () => import('./web').then((m) => new m.DeviceIntegrityWeb()),\n});\nexport * from './definitions';\nexport { DeviceIntegrity };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nconst WEB_ERROR_MESSAGE = 'Device integrity is not available on web. Use the native Android or iOS implementation.';\nexport class DeviceIntegrityWeb extends WebPlugin {\n async getCapabilities() {\n return {\n platform: 'web',\n widevine: {\n supported: false,\n fingerprintAvailable: false,\n securityLevelScanSupported: false,\n },\n appAttest: { supported: false },\n deviceCheck: { supported: false },\n playIntegrity: { supported: false },\n };\n }\n async getWidevineFingerprint(_options) {\n void _options;\n throw new Error(WEB_ERROR_MESSAGE);\n }\n async prepareAttestation(_options) {\n void _options;\n throw new Error(WEB_ERROR_MESSAGE);\n }\n async createAttestation(_options) {\n void _options;\n throw new Error(WEB_ERROR_MESSAGE);\n }\n async createAssertion(_options) {\n void _options;\n throw new Error(WEB_ERROR_MESSAGE);\n }\n async getDeviceCheckToken() {\n throw new Error(WEB_ERROR_MESSAGE);\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,eAAe,GAAGA,mBAAc,CAAC,iBAAiB,EAAE;IAC1D,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,kBAAkB,EAAE,CAAC;IACtE,CAAC;;ICFD,MAAM,iBAAiB,GAAG,yFAAyF;IAC5G,MAAM,kBAAkB,SAASC,cAAS,CAAC;IAClD,IAAI,MAAM,eAAe,GAAG;IAC5B,QAAQ,OAAO;IACf,YAAY,QAAQ,EAAE,KAAK;IAC3B,YAAY,QAAQ,EAAE;IACtB,gBAAgB,SAAS,EAAE,KAAK;IAChC,gBAAgB,oBAAoB,EAAE,KAAK;IAC3C,gBAAgB,0BAA0B,EAAE,KAAK;IACjD,aAAa;IACb,YAAY,SAAS,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE;IAC3C,YAAY,WAAW,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE;IAC7C,YAAY,aAAa,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE;IAC/C,SAAS;IACT,IAAI;IACJ,IAAI,MAAM,sBAAsB,CAAC,QAAQ,EAAE;IAE3C,QAAQ,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC;IAC1C,IAAI;IACJ,IAAI,MAAM,kBAAkB,CAAC,QAAQ,EAAE;IAEvC,QAAQ,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC;IAC1C,IAAI;IACJ,IAAI,MAAM,iBAAiB,CAAC,QAAQ,EAAE;IAEtC,QAAQ,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC;IAC1C,IAAI;IACJ,IAAI,MAAM,eAAe,CAAC,QAAQ,EAAE;IAEpC,QAAQ,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC;IAC1C,IAAI;IACJ,IAAI,MAAM,mBAAmB,GAAG;IAChC,QAAQ,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC;IAC1C,IAAI;IACJ;;;;;;;;;;;;;;;"}
@@ -0,0 +1,49 @@
1
+ import CryptoKit
2
+ import DeviceCheck
3
+ import Foundation
4
+
5
+ @objc public class DeviceIntegrity: NSObject {
6
+ @objc public func isAppAttestSupported() -> Bool {
7
+ return DCAppAttestService.shared.isSupported
8
+ }
9
+
10
+ @objc public func isDeviceCheckSupported() -> Bool {
11
+ return DCDevice.current.isSupported
12
+ }
13
+
14
+ public func createClientDataHash(from input: String) throws -> Data {
15
+ guard let payloadData = input.data(using: .utf8) else {
16
+ throw DeviceIntegrityError.invalidInput
17
+ }
18
+ return Data(SHA256.hash(data: payloadData))
19
+ }
20
+ }
21
+
22
+ public enum DeviceIntegrityError: LocalizedError {
23
+ case appAttestNotSupported
24
+ case deviceCheckNotSupported
25
+ case missingKeyId
26
+ case missingChallenge
27
+ case missingPayload
28
+ case missingGeneratedValue
29
+ case invalidInput
30
+
31
+ public var errorDescription: String? {
32
+ switch self {
33
+ case .appAttestNotSupported:
34
+ return "App Attest is not supported on this device"
35
+ case .deviceCheckNotSupported:
36
+ return "DeviceCheck is not supported on this device"
37
+ case .missingKeyId:
38
+ return "keyId is required"
39
+ case .missingChallenge:
40
+ return "challenge is required"
41
+ case .missingPayload:
42
+ return "payload is required"
43
+ case .missingGeneratedValue:
44
+ return "Native API returned no value"
45
+ case .invalidInput:
46
+ return "Invalid input format"
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,208 @@
1
+ import Capacitor
2
+ import DeviceCheck
3
+ import Foundation
4
+
5
+ @objc(DeviceIntegrityPlugin)
6
+ public class DeviceIntegrityPlugin: CAPPlugin, CAPBridgedPlugin {
7
+ public let identifier = "DeviceIntegrityPlugin"
8
+ public let jsName = "DeviceIntegrity"
9
+ public let pluginMethods: [CAPPluginMethod] = [
10
+ CAPPluginMethod(name: "getCapabilities", returnType: CAPPluginReturnPromise),
11
+ CAPPluginMethod(name: "getWidevineFingerprint", returnType: CAPPluginReturnPromise),
12
+ CAPPluginMethod(name: "prepareAttestation", returnType: CAPPluginReturnPromise),
13
+ CAPPluginMethod(name: "createAttestation", returnType: CAPPluginReturnPromise),
14
+ CAPPluginMethod(name: "createAssertion", returnType: CAPPluginReturnPromise),
15
+ CAPPluginMethod(name: "getDeviceCheckToken", returnType: CAPPluginReturnPromise)
16
+ ]
17
+
18
+ private let implementation = DeviceIntegrity()
19
+ private let appAttestFormat = "apple-app-attest"
20
+
21
+ @objc func getCapabilities(_ call: CAPPluginCall) {
22
+ call.resolve([
23
+ "platform": "ios",
24
+ "widevine": [
25
+ "supported": false,
26
+ "fingerprintAvailable": false,
27
+ "securityLevelScanSupported": false
28
+ ],
29
+ "appAttest": [
30
+ "supported": implementation.isAppAttestSupported()
31
+ ],
32
+ "deviceCheck": [
33
+ "supported": implementation.isDeviceCheckSupported()
34
+ ],
35
+ "playIntegrity": [
36
+ "supported": false
37
+ ]
38
+ ])
39
+ }
40
+
41
+ @objc func getWidevineFingerprint(_ call: CAPPluginCall) {
42
+ call.reject("Widevine fingerprinting is only available on Android")
43
+ }
44
+
45
+ @objc func prepareAttestation(_ call: CAPPluginCall) {
46
+ do {
47
+ try validateAppAttestSupport()
48
+
49
+ DCAppAttestService.shared.generateKey { [weak self] keyId, error in
50
+ guard let self else {
51
+ return
52
+ }
53
+
54
+ if let error {
55
+ self.reject(call, message: "Error generating App Attest key: \(error.localizedDescription)", error: error)
56
+ return
57
+ }
58
+
59
+ guard let keyId else {
60
+ self.reject(call, message: DeviceIntegrityError.missingGeneratedValue.localizedDescription)
61
+ return
62
+ }
63
+
64
+ self.resolve(call, payload: [
65
+ "keyId": keyId,
66
+ "format": self.appAttestFormat
67
+ ])
68
+ }
69
+ } catch {
70
+ reject(call, message: error.localizedDescription, error: error)
71
+ }
72
+ }
73
+
74
+ @objc func createAttestation(_ call: CAPPluginCall) {
75
+ do {
76
+ try validateAppAttestSupport()
77
+ let keyId = try keyId(from: call)
78
+ let challenge = try challenge(from: call)
79
+ let clientDataHash = try implementation.createClientDataHash(from: challenge)
80
+
81
+ DCAppAttestService.shared.attestKey(keyId, clientDataHash: clientDataHash) { [weak self] attestation, error in
82
+ guard let self else {
83
+ return
84
+ }
85
+
86
+ if let error {
87
+ self.reject(call, message: "Error creating App Attest token: \(error.localizedDescription)", error: error)
88
+ return
89
+ }
90
+
91
+ guard let attestation else {
92
+ self.reject(call, message: DeviceIntegrityError.missingGeneratedValue.localizedDescription)
93
+ return
94
+ }
95
+
96
+ self.resolve(call, payload: [
97
+ "token": attestation.base64EncodedString(),
98
+ "keyId": keyId,
99
+ "format": self.appAttestFormat
100
+ ])
101
+ }
102
+ } catch {
103
+ reject(call, message: error.localizedDescription, error: error)
104
+ }
105
+ }
106
+
107
+ @objc func createAssertion(_ call: CAPPluginCall) {
108
+ do {
109
+ try validateAppAttestSupport()
110
+ let keyId = try keyId(from: call)
111
+ let payload = try payload(from: call)
112
+ let clientDataHash = try implementation.createClientDataHash(from: payload)
113
+
114
+ DCAppAttestService.shared.generateAssertion(keyId, clientDataHash: clientDataHash) { [weak self] assertion, error in
115
+ guard let self else {
116
+ return
117
+ }
118
+
119
+ if let error {
120
+ self.reject(call, message: "Error creating App Attest assertion: \(error.localizedDescription)", error: error)
121
+ return
122
+ }
123
+
124
+ guard let assertion else {
125
+ self.reject(call, message: DeviceIntegrityError.missingGeneratedValue.localizedDescription)
126
+ return
127
+ }
128
+
129
+ self.resolve(call, payload: [
130
+ "token": assertion.base64EncodedString(),
131
+ "keyId": keyId,
132
+ "format": self.appAttestFormat
133
+ ])
134
+ }
135
+ } catch {
136
+ reject(call, message: error.localizedDescription, error: error)
137
+ }
138
+ }
139
+
140
+ @objc func getDeviceCheckToken(_ call: CAPPluginCall) {
141
+ do {
142
+ guard implementation.isDeviceCheckSupported() else {
143
+ throw DeviceIntegrityError.deviceCheckNotSupported
144
+ }
145
+
146
+ DCDevice.current.generateToken { [weak self] token, error in
147
+ guard let self else {
148
+ return
149
+ }
150
+
151
+ if let error {
152
+ self.reject(call, message: "Error generating DeviceCheck token: \(error.localizedDescription)", error: error)
153
+ return
154
+ }
155
+
156
+ guard let token else {
157
+ self.reject(call, message: DeviceIntegrityError.missingGeneratedValue.localizedDescription)
158
+ return
159
+ }
160
+
161
+ self.resolve(call, payload: [
162
+ "token": token.base64EncodedString()
163
+ ])
164
+ }
165
+ } catch {
166
+ reject(call, message: error.localizedDescription, error: error)
167
+ }
168
+ }
169
+
170
+ private func validateAppAttestSupport() throws {
171
+ guard implementation.isAppAttestSupported() else {
172
+ throw DeviceIntegrityError.appAttestNotSupported
173
+ }
174
+ }
175
+
176
+ private func keyId(from call: CAPPluginCall) throws -> String {
177
+ guard let keyId = call.getString("keyId"), !keyId.isEmpty else {
178
+ throw DeviceIntegrityError.missingKeyId
179
+ }
180
+ return keyId
181
+ }
182
+
183
+ private func challenge(from call: CAPPluginCall) throws -> String {
184
+ guard let challenge = call.getString("challenge"), !challenge.isEmpty else {
185
+ throw DeviceIntegrityError.missingChallenge
186
+ }
187
+ return challenge
188
+ }
189
+
190
+ private func payload(from call: CAPPluginCall) throws -> String {
191
+ guard let payload = call.getString("payload"), !payload.isEmpty else {
192
+ throw DeviceIntegrityError.missingPayload
193
+ }
194
+ return payload
195
+ }
196
+
197
+ private func resolve(_ call: CAPPluginCall, payload: [String: Any]) {
198
+ DispatchQueue.main.async {
199
+ call.resolve(payload)
200
+ }
201
+ }
202
+
203
+ private func reject(_ call: CAPPluginCall, message: String, error: Error? = nil) {
204
+ DispatchQueue.main.async {
205
+ call.reject(message, nil, error)
206
+ }
207
+ }
208
+ }
@@ -0,0 +1,24 @@
1
+ import CryptoKit
2
+ import XCTest
3
+ @testable import DeviceIntegrityPlugin
4
+
5
+ final class DeviceIntegrityTests: XCTestCase {
6
+ func testCreateClientDataHashUsesSha256() throws {
7
+ let implementation = DeviceIntegrity()
8
+ let payload = "server-issued-challenge"
9
+
10
+ let result = try implementation.createClientDataHash(from: payload)
11
+ let expected = Data(SHA256.hash(data: Data(payload.utf8)))
12
+
13
+ XCTAssertEqual(result, expected)
14
+ }
15
+
16
+ func testSupportChecksReturnBooleanValues() {
17
+ let implementation = DeviceIntegrity()
18
+ let appAttestSupported = implementation.isAppAttestSupported()
19
+ let deviceCheckSupported = implementation.isDeviceCheckSupported()
20
+
21
+ XCTAssertTrue(appAttestSupported || !appAttestSupported)
22
+ XCTAssertTrue(deviceCheckSupported || !deviceCheckSupported)
23
+ }
24
+ }
package/package.json ADDED
@@ -0,0 +1,92 @@
1
+ {
2
+ "name": "@capgo/capacitor-device-integrity",
3
+ "version": "8.0.2",
4
+ "description": "Device integrity and fraud signals for Capacitor using Android Widevine, Play Integrity, iOS App Attest, and DeviceCheck.",
5
+ "main": "dist/plugin.cjs.js",
6
+ "module": "dist/esm/index.js",
7
+ "types": "dist/esm/index.d.ts",
8
+ "unpkg": "dist/plugin.js",
9
+ "files": [
10
+ "android/src/main/",
11
+ "android/build.gradle",
12
+ "dist/",
13
+ "ios/Sources",
14
+ "ios/Tests",
15
+ "Package.swift",
16
+ "CapgoCapacitorDeviceIntegrity.podspec"
17
+ ],
18
+ "author": "Martin Donadieu <martin@capgo.app>",
19
+ "license": "MPL-2.0",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/Cap-go/capacitor-device-integrity.git"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/Cap-go/capacitor-device-integrity/issues"
26
+ },
27
+ "homepage": "https://capgo.app/docs/plugins/device-integrity/",
28
+ "keywords": [
29
+ "capacitor",
30
+ "device-integrity",
31
+ "fraud-detection",
32
+ "widevine",
33
+ "app-attest",
34
+ "devicecheck",
35
+ "play-integrity",
36
+ "capgo"
37
+ ],
38
+ "scripts": {
39
+ "verify": "bun run verify:ios && bun run verify:android && bun run verify:web",
40
+ "verify:ios": "xcodebuild -scheme CapgoCapacitorDeviceIntegrity -destination generic/platform=iOS",
41
+ "verify:android": "cd android && ./gradlew clean build test && cd ..",
42
+ "verify:web": "bun run build",
43
+ "lint": "bun run eslint && bun run prettier -- --check && bun run swiftlint -- lint",
44
+ "fmt": "bun run eslint -- --fix && bun run prettier -- --write && bun run swiftlint -- --fix --format",
45
+ "eslint": "eslint . --ext .ts",
46
+ "prettier": "prettier-pretty-check \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
47
+ "swiftlint": "node-swiftlint",
48
+ "docgen": "docgen --api DeviceIntegrityPlugin --output-readme README.md --output-json dist/docs.json",
49
+ "build": "bun run clean && bun run docgen && tsc && rollup -c rollup.config.mjs",
50
+ "clean": "rimraf ./dist",
51
+ "watch": "tsc --watch",
52
+ "prepublishOnly": "bun run build",
53
+ "check:wiring": "node scripts/check-capacitor-plugin-wiring.mjs"
54
+ },
55
+ "devDependencies": {
56
+ "@capacitor/android": "^8.0.0",
57
+ "@capacitor/cli": "^8.0.0",
58
+ "@capacitor/core": "^8.0.0",
59
+ "@capacitor/docgen": "^0.3.1",
60
+ "@capacitor/ios": "^8.0.0",
61
+ "@ionic/eslint-config": "^0.4.0",
62
+ "@ionic/prettier-config": "^4.0.0",
63
+ "@ionic/swiftlint-config": "^2.0.0",
64
+ "@types/node": "^24.10.1",
65
+ "eslint": "^8.57.1",
66
+ "eslint-plugin-import": "^2.31.0",
67
+ "husky": "^9.1.7",
68
+ "prettier": "^3.6.2",
69
+ "prettier-pretty-check": "^0.2.0",
70
+ "prettier-plugin-java": "^2.7.7",
71
+ "rimraf": "^6.1.0",
72
+ "rollup": "^4.53.2",
73
+ "swiftlint": "^2.0.0",
74
+ "typescript": "^5.9.3"
75
+ },
76
+ "peerDependencies": {
77
+ "@capacitor/core": ">=8.0.0"
78
+ },
79
+ "prettier": "@ionic/prettier-config",
80
+ "swiftlint": "@ionic/swiftlint-config",
81
+ "eslintConfig": {
82
+ "extends": "@ionic/eslint-config/recommended"
83
+ },
84
+ "capacitor": {
85
+ "ios": {
86
+ "src": "ios"
87
+ },
88
+ "android": {
89
+ "src": "android"
90
+ }
91
+ }
92
+ }