idmission-web-sdk 2.3.212 → 2.3.213
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/dist/lib/camera/Camera.d.ts +7 -3
- package/dist/lib/camera/Camera.d.ts.map +1 -1
- package/dist/lib/camera/cameraStore.d.ts.map +1 -1
- package/dist/lib/camera/getUserMediaIntegrity.d.ts +49 -8
- package/dist/lib/camera/getUserMediaIntegrity.d.ts.map +1 -1
- package/dist/lib/camera/getUserMediaIntegrity.test.d.ts +2 -0
- package/dist/lib/camera/getUserMediaIntegrity.test.d.ts.map +1 -0
- package/dist/sdk2.cjs.development.js +136 -29
- package/dist/sdk2.cjs.development.js.map +1 -1
- package/dist/sdk2.cjs.production.js +1 -1
- package/dist/sdk2.cjs.production.js.map +1 -1
- package/dist/sdk2.esm.js +136 -29
- package/dist/sdk2.esm.js.map +1 -1
- package/dist/sdk2.umd.development.js +136 -29
- package/dist/sdk2.umd.development.js.map +1 -1
- package/dist/sdk2.umd.production.js +1 -1
- package/dist/sdk2.umd.production.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { type MediaIntegrityToken } from './getUserMediaIntegrity';
|
|
2
|
+
type TamperOptions = {
|
|
3
|
+
enabled?: boolean;
|
|
4
|
+
token?: MediaIntegrityToken;
|
|
5
|
+
};
|
|
2
6
|
export type Camera = {
|
|
3
7
|
stream: MediaStream;
|
|
4
8
|
isRearFacing: boolean;
|
|
@@ -8,8 +12,8 @@ export type Camera = {
|
|
|
8
12
|
height: number;
|
|
9
13
|
};
|
|
10
14
|
export type CameraResolution = 'LOW' | 'MID' | 'MAX';
|
|
11
|
-
export declare function selectAndOpenCamera(resolution?: CameraResolution,
|
|
12
|
-
export declare function getVideoDeviceMaxDimensions(deviceInfo: MediaDeviceInfo,
|
|
15
|
+
export declare function selectAndOpenCamera(resolution?: CameraResolution, tamper?: TamperOptions): Promise<Camera>;
|
|
16
|
+
export declare function getVideoDeviceMaxDimensions(deviceInfo: MediaDeviceInfo, tamper?: TamperOptions): Promise<{
|
|
13
17
|
width: number;
|
|
14
18
|
height: number;
|
|
15
19
|
}>;
|
|
@@ -21,7 +25,7 @@ type Resolution = {
|
|
|
21
25
|
};
|
|
22
26
|
export declare const quickScan: Resolution[];
|
|
23
27
|
export type FacingMode = 'user' | 'environment' | 'left' | 'right';
|
|
24
|
-
export declare function listAvailableCameras(facingMode?: FacingMode, requestMicAccess?: boolean,
|
|
28
|
+
export declare function listAvailableCameras(facingMode?: FacingMode, requestMicAccess?: boolean, tamper?: TamperOptions): Promise<MediaDeviceInfo[]>;
|
|
25
29
|
export declare const frontCameraLabels: string[];
|
|
26
30
|
export declare const rearCameraLabels: string[];
|
|
27
31
|
export declare const backUltraWideCameraLabels: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Camera.d.ts","sourceRoot":"","sources":["../../../src/lib/camera/Camera.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,KAAK,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAIrF,MAAM,MAAM,MAAM,GAAG;IACnB,MAAM,EAAE,WAAW,CAAA;IACnB,YAAY,EAAE,OAAO,CAAA;IACrB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAA;AAIpD,wBAAsB,mBAAmB,CACvC,UAAU,GAAE,gBAAwB,EACpC,
|
|
1
|
+
{"version":3,"file":"Camera.d.ts","sourceRoot":"","sources":["../../../src/lib/camera/Camera.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,KAAK,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAIrF,KAAK,aAAa,GAAG;IACnB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,mBAAmB,CAAA;CAC5B,CAAA;AAED,MAAM,MAAM,MAAM,GAAG;IACnB,MAAM,EAAE,WAAW,CAAA;IACnB,YAAY,EAAE,OAAO,CAAA;IACrB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAA;AAIpD,wBAAsB,mBAAmB,CACvC,UAAU,GAAE,gBAAwB,EACpC,MAAM,GAAE,aAAkB,GACzB,OAAO,CAAC,MAAM,CAAC,CA2GjB;AAQD,wBAAsB,2BAA2B,CAC/C,UAAU,EAAE,eAAe,EAC3B,MAAM,GAAE,aAAkB,GACzB,OAAO,CAAC;IACT,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf,CAAC,CAkBD;AAED,KAAK,UAAU,GAAG;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AACD,eAAO,MAAM,SAAS,EAAE,UAAU,EAmEjC,CAAA;AAyFD,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,aAAa,GAAG,MAAM,GAAG,OAAO,CAAA;AAElE,wBAAsB,oBAAoB,CACxC,UAAU,CAAC,EAAE,UAAU,EACvB,gBAAgB,GAAE,OAAe,EACjC,MAAM,GAAE,aAAkB,GACzB,OAAO,CAAC,eAAe,EAAE,CAAC,CA2B5B;AAED,eAAO,MAAM,iBAAiB,UA+ByB,CAAA;AACvD,eAAO,MAAM,gBAAgB,UAoC0B,CAAA;AACvD,eAAO,MAAM,yBAAyB,UAqCiB,CAAA;AAEvD,eAAO,MAAM,kBAAkB,kBACd,MAAM,GAAG,eAAe,mBACtB,MAAM,GAAG,MAAM,EAAE,YAWnC,CAAA;AAQD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAC9B,MAAM,CA6CR;AAED,wBAAgB,mBAAmB,SAKlC;AAED,wBAAgB,uBAAuB,SAQtC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cameraStore.d.ts","sourceRoot":"","sources":["../../../src/lib/camera/cameraStore.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"cameraStore.d.ts","sourceRoot":"","sources":["../../../src/lib/camera/cameraStore.tsx"],"names":[],"mappings":"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"}
|
|
@@ -12,20 +12,61 @@ export type IntegrityResult = {
|
|
|
12
12
|
* Customers should call this as early as possible in their application boot,
|
|
13
13
|
* before any third-party scripts have a chance to monkey-patch browser APIs.
|
|
14
14
|
*
|
|
15
|
-
* The returned token is passed to SDK components via the `mediaIntegrityToken`
|
|
15
|
+
* The returned token is passed to SDK components via the `mediaIntegrityToken`
|
|
16
|
+
* prop. **Passing a token is the recommended way to enable strong tamper
|
|
17
|
+
* detection.** Without it, the SDK falls back to Layer 1 (boot-time reference
|
|
18
|
+
* snapshot) and Layer 2 (page-vs-iframe `toString` heuristic), both of which
|
|
19
|
+
* are best-effort and can produce false positives — e.g. legitimate post-init
|
|
20
|
+
* shims like `webrtc-adapter`, browser-level instrumentation in Chrome for
|
|
21
|
+
* iOS (CriOS), and some browser extensions all replace `getUserMedia` in ways
|
|
22
|
+
* that look indistinguishable from tampering at those layers.
|
|
23
|
+
*
|
|
24
|
+
* Layer 3 (this token) compares against a snapshot the customer captures at
|
|
25
|
+
* a moment of their choosing, so it is robust against post-capture tampering
|
|
26
|
+
* regardless of how sophisticated the attacker is at faking `[native code]`
|
|
27
|
+
* after the snapshot — but it cannot defend against tampering that already
|
|
28
|
+
* happened before `captureMediaIntegrity` ran. Capture early.
|
|
29
|
+
*
|
|
30
|
+
* **Must be called in a browser context** (`navigator.mediaDevices` available).
|
|
31
|
+
* Calling during SSR / pre-DOM produces a token whose snapshot is empty;
|
|
32
|
+
* subsequent integrity checks against such a token will report "unrecognized
|
|
33
|
+
* or forged token" — a false positive caused by capture-time misuse.
|
|
16
34
|
*/
|
|
17
35
|
export declare function captureMediaIntegrity(): MediaIntegrityToken;
|
|
36
|
+
export type IntegrityCheckOptions = {
|
|
37
|
+
/** When false or omitted, all checks are skipped and result is clean. */
|
|
38
|
+
enabled?: boolean;
|
|
39
|
+
/** Optional customer-captured token for Layer 3. */
|
|
40
|
+
token?: MediaIntegrityToken;
|
|
41
|
+
};
|
|
18
42
|
/**
|
|
19
43
|
* Run all applicable integrity check layers.
|
|
20
|
-
*
|
|
21
|
-
* Layer
|
|
22
|
-
*
|
|
44
|
+
*
|
|
45
|
+
* - **Layer 1**: Boot-time referential equality (corroborated by Layer 2).
|
|
46
|
+
* Best-effort; misses attackers who inject before SDK load.
|
|
47
|
+
* - **Layer 2**: Fresh-iframe cross-realm `toString` comparison. Best-effort;
|
|
48
|
+
* produces false positives in browser-level instrumentation contexts (CriOS,
|
|
49
|
+
* extensions). The page-vs-iframe disagreement case is gated on iframe
|
|
50
|
+
* trustworthiness to mitigate this.
|
|
51
|
+
* - **Layer 3**: Customer-provided token validation (only runs when a token
|
|
52
|
+
* is supplied). **This is the strong defense** — see `captureMediaIntegrity`.
|
|
53
|
+
*
|
|
54
|
+
* Returns clean immediately if `enabled` is not true.
|
|
23
55
|
*/
|
|
24
|
-
export declare function checkGetUserMediaIntegrity(
|
|
56
|
+
export declare function checkGetUserMediaIntegrity(options?: IntegrityCheckOptions): IntegrityResult;
|
|
25
57
|
/**
|
|
26
|
-
* Lightweight pre-call guard
|
|
27
|
-
* Returns `
|
|
58
|
+
* Lightweight pre-call guard. Returns `true` if tampering is detected.
|
|
59
|
+
* Returns `false` immediately when not enabled.
|
|
60
|
+
*
|
|
61
|
+
* Runs Layer 1 (corroborated by a cached Layer 2 verdict) and Layer 3.
|
|
62
|
+
* The full check at mount time (`checkGetUserMediaIntegrity`) re-runs Layer 2
|
|
63
|
+
* fresh for completeness; this guard uses the cache so per-call cost is low.
|
|
64
|
+
*
|
|
65
|
+
* For strong tamper resistance, customers should pass a token captured via
|
|
66
|
+
* `captureMediaIntegrity` — Layer 1 is best-effort and can produce false
|
|
67
|
+
* positives against legitimate post-init shims (`webrtc-adapter`, polyfills,
|
|
68
|
+
* browser extensions).
|
|
28
69
|
*/
|
|
29
|
-
export declare function guardGetUserMedia(
|
|
70
|
+
export declare function guardGetUserMedia(options?: IntegrityCheckOptions): boolean;
|
|
30
71
|
export {};
|
|
31
72
|
//# sourceMappingURL=getUserMediaIntegrity.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getUserMediaIntegrity.d.ts","sourceRoot":"","sources":["../../../src/lib/camera/getUserMediaIntegrity.ts"],"names":[],"mappings":"AAcA,OAAO,CAAC,MAAM,wBAAwB,EAAE,OAAO,MAAM,CAAA;AAErD,iFAAiF;AACjF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,CAAC,wBAAwB,CAAC,EAAE,IAAI,CAAA;CAC1C,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB,CAAA;
|
|
1
|
+
{"version":3,"file":"getUserMediaIntegrity.d.ts","sourceRoot":"","sources":["../../../src/lib/camera/getUserMediaIntegrity.ts"],"names":[],"mappings":"AAcA,OAAO,CAAC,MAAM,wBAAwB,EAAE,OAAO,MAAM,CAAA;AAErD,iFAAiF;AACjF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,CAAC,wBAAwB,CAAC,EAAE,IAAI,CAAA;CAC1C,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,OAAO,CAAA;IACjB,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB,CAAA;AA+BD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,IAAI,mBAAmB,CAS3D;AAsLD,MAAM,MAAM,qBAAqB,GAAG;IAClC,yEAAyE;IACzE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,oDAAoD;IACpD,KAAK,CAAC,EAAE,mBAAmB,CAAA;CAC5B,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,GAAE,qBAA0B,GAClC,eAAe,CAwBjB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAiBT"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getUserMediaIntegrity.test.d.ts","sourceRoot":"","sources":["../../../src/lib/camera/getUserMediaIntegrity.test.ts"],"names":[],"mappings":""}
|
|
@@ -235,7 +235,7 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
|
|
|
235
235
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
236
236
|
};
|
|
237
237
|
|
|
238
|
-
var webSdkVersion = '2.3.
|
|
238
|
+
var webSdkVersion = '2.3.213';
|
|
239
239
|
|
|
240
240
|
function getPlatform() {
|
|
241
241
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
@@ -4194,6 +4194,24 @@ var LOG_TAG$2 = 'camera:getUserMediaIntegrity';
|
|
|
4194
4194
|
// Module-level boot-time cached references (SSR-safe)
|
|
4195
4195
|
var _createElement = typeof document !== 'undefined' ? Document.prototype.createElement : undefined;
|
|
4196
4196
|
var _getUserMedia = typeof navigator !== 'undefined' ? (_a = navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.getUserMedia : undefined;
|
|
4197
|
+
// Cached Layer 2 verdict — Layer 2 creates an iframe (expensive). Cache the
|
|
4198
|
+
// result for the lifetime of the page so repeated guard() calls are cheap.
|
|
4199
|
+
// Keyed by the current navigator.mediaDevices.getUserMedia identity so a
|
|
4200
|
+
// post-init replacement re-runs Layer 2 once and the new verdict sticks.
|
|
4201
|
+
var _cachedLayer2;
|
|
4202
|
+
function getCachedLayer2Verdict() {
|
|
4203
|
+
var _a;
|
|
4204
|
+
var currentSource = typeof navigator !== 'undefined' ? (_a = navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.getUserMedia : undefined;
|
|
4205
|
+
if (_cachedLayer2 && _cachedLayer2.source === currentSource) {
|
|
4206
|
+
return _cachedLayer2.verdict;
|
|
4207
|
+
}
|
|
4208
|
+
var verdict = checkLayer2();
|
|
4209
|
+
_cachedLayer2 = {
|
|
4210
|
+
source: currentSource,
|
|
4211
|
+
verdict: verdict
|
|
4212
|
+
};
|
|
4213
|
+
return verdict;
|
|
4214
|
+
}
|
|
4197
4215
|
// --- Layer 3: Customer-provided token ---
|
|
4198
4216
|
var tokenStore = new WeakMap();
|
|
4199
4217
|
/**
|
|
@@ -4201,7 +4219,25 @@ var tokenStore = new WeakMap();
|
|
|
4201
4219
|
* Customers should call this as early as possible in their application boot,
|
|
4202
4220
|
* before any third-party scripts have a chance to monkey-patch browser APIs.
|
|
4203
4221
|
*
|
|
4204
|
-
* The returned token is passed to SDK components via the `mediaIntegrityToken`
|
|
4222
|
+
* The returned token is passed to SDK components via the `mediaIntegrityToken`
|
|
4223
|
+
* prop. **Passing a token is the recommended way to enable strong tamper
|
|
4224
|
+
* detection.** Without it, the SDK falls back to Layer 1 (boot-time reference
|
|
4225
|
+
* snapshot) and Layer 2 (page-vs-iframe `toString` heuristic), both of which
|
|
4226
|
+
* are best-effort and can produce false positives — e.g. legitimate post-init
|
|
4227
|
+
* shims like `webrtc-adapter`, browser-level instrumentation in Chrome for
|
|
4228
|
+
* iOS (CriOS), and some browser extensions all replace `getUserMedia` in ways
|
|
4229
|
+
* that look indistinguishable from tampering at those layers.
|
|
4230
|
+
*
|
|
4231
|
+
* Layer 3 (this token) compares against a snapshot the customer captures at
|
|
4232
|
+
* a moment of their choosing, so it is robust against post-capture tampering
|
|
4233
|
+
* regardless of how sophisticated the attacker is at faking `[native code]`
|
|
4234
|
+
* after the snapshot — but it cannot defend against tampering that already
|
|
4235
|
+
* happened before `captureMediaIntegrity` ran. Capture early.
|
|
4236
|
+
*
|
|
4237
|
+
* **Must be called in a browser context** (`navigator.mediaDevices` available).
|
|
4238
|
+
* Calling during SSR / pre-DOM produces a token whose snapshot is empty;
|
|
4239
|
+
* subsequent integrity checks against such a token will report "unrecognized
|
|
4240
|
+
* or forged token" — a false positive caused by capture-time misuse.
|
|
4205
4241
|
*/
|
|
4206
4242
|
function captureMediaIntegrity() {
|
|
4207
4243
|
var token = Object.freeze({
|
|
@@ -4215,8 +4251,8 @@ function captureMediaIntegrity() {
|
|
|
4215
4251
|
}
|
|
4216
4252
|
return token;
|
|
4217
4253
|
}
|
|
4218
|
-
// --- Layer 1: Boot-time referential equality ---
|
|
4219
|
-
function checkLayer1() {
|
|
4254
|
+
// --- Layer 1: Boot-time referential equality (with Layer 2 corroboration) ---
|
|
4255
|
+
function checkLayer1(layer2) {
|
|
4220
4256
|
var details = [];
|
|
4221
4257
|
// SSR or missing mediaDevices — pass gracefully
|
|
4222
4258
|
if (!_getUserMedia || typeof navigator === 'undefined' || !navigator.mediaDevices) {
|
|
@@ -4225,8 +4261,19 @@ function checkLayer1() {
|
|
|
4225
4261
|
details: details
|
|
4226
4262
|
};
|
|
4227
4263
|
}
|
|
4228
|
-
if (navigator.mediaDevices.getUserMedia
|
|
4229
|
-
|
|
4264
|
+
if (navigator.mediaDevices.getUserMedia === _getUserMedia) {
|
|
4265
|
+
return {
|
|
4266
|
+
tampered: false,
|
|
4267
|
+
details: details
|
|
4268
|
+
};
|
|
4269
|
+
}
|
|
4270
|
+
// Reference differs from boot snapshot. This may be a legitimate post-init
|
|
4271
|
+
// shim (webrtc-adapter, polyfill, browser extension). Only flag when Layer 2
|
|
4272
|
+
// gives positive evidence of tampering. If Layer 2 is unavailable (no
|
|
4273
|
+
// document) or itself reports clean, defer to Layer 2's signal and don't
|
|
4274
|
+
// double-report at Layer 1.
|
|
4275
|
+
if (layer2 === null || layer2 === void 0 ? void 0 : layer2.tampered) {
|
|
4276
|
+
details.push('Layer 1: navigator.mediaDevices.getUserMedia reference differs from boot-time snapshot (corroborated by Layer 2)');
|
|
4230
4277
|
}
|
|
4231
4278
|
return {
|
|
4232
4279
|
tampered: details.length > 0,
|
|
@@ -4235,7 +4282,7 @@ function checkLayer1() {
|
|
|
4235
4282
|
}
|
|
4236
4283
|
// --- Layer 2: Fresh iframe cross-context toString ---
|
|
4237
4284
|
function checkLayer2() {
|
|
4238
|
-
var _a, _b;
|
|
4285
|
+
var _a, _b, _c, _d;
|
|
4239
4286
|
var details = [];
|
|
4240
4287
|
// SSR or missing prerequisites — pass gracefully
|
|
4241
4288
|
if (typeof document === 'undefined' || !_createElement || !navigator.mediaDevices) {
|
|
@@ -4281,8 +4328,24 @@ function checkLayer2() {
|
|
|
4281
4328
|
// Neither is native — something has tampered at a deep level
|
|
4282
4329
|
details.push('Layer 2: neither page nor iframe getUserMedia appear native');
|
|
4283
4330
|
} else if (pageIsNative && !iframeIsNative) {
|
|
4284
|
-
//
|
|
4285
|
-
|
|
4331
|
+
// Iframe disagrees with page about native-ness. Probe iframe
|
|
4332
|
+
// trustworthiness via another mediaDevices method before deciding
|
|
4333
|
+
// whether to flag. Browsers (Chrome for iOS / CriOS) and some
|
|
4334
|
+
// extensions wrap iframe getUserMedia specifically while leaving
|
|
4335
|
+
// sibling methods intact; broadly-tampered iframes also can't be
|
|
4336
|
+
// trusted as a "what does native look like" reference. In neither
|
|
4337
|
+
// case is the iframe a reliable witness, so we trust the page-
|
|
4338
|
+
// level [native code] signal and don't flag here.
|
|
4339
|
+
//
|
|
4340
|
+
// The strong defense against a faked-native page-level impostor
|
|
4341
|
+
// is Layer 3 (customer-captured token), not Layer 2 heuristics.
|
|
4342
|
+
var iframeEnumerateDevices = (_d = (_c = iframeWindow.navigator) === null || _c === void 0 ? void 0 : _c.mediaDevices) === null || _d === void 0 ? void 0 : _d.enumerateDevices;
|
|
4343
|
+
var iframeEnumerateNative = iframeEnumerateDevices ? String(iframeToString.call(iframeEnumerateDevices)).includes('[native code]') : false;
|
|
4344
|
+
if (iframeEnumerateNative) {
|
|
4345
|
+
debug("".concat(LOG_TAG$2, " Layer 2: page getUserMedia native; iframe getUserMedia wrapped but iframe enumerateDevices native \u2014 browser-level instrumentation pattern (e.g. CriOS), not flagged"));
|
|
4346
|
+
} else {
|
|
4347
|
+
debug("".concat(LOG_TAG$2, " Layer 2: page getUserMedia native; iframe broadly unreliable as a reference (enumerateDevices also non-native or unavailable), not flagged"));
|
|
4348
|
+
}
|
|
4286
4349
|
}
|
|
4287
4350
|
// pageIsNative=false, iframeIsNative=true → legitimate shim (e.g. adapter.js), not flagged
|
|
4288
4351
|
// both native → clean, not flagged
|
|
@@ -4343,20 +4406,36 @@ function checkLayer3(token) {
|
|
|
4343
4406
|
details: details
|
|
4344
4407
|
};
|
|
4345
4408
|
}
|
|
4346
|
-
// --- Public API ---
|
|
4347
4409
|
/**
|
|
4348
4410
|
* Run all applicable integrity check layers.
|
|
4349
|
-
*
|
|
4350
|
-
* Layer
|
|
4351
|
-
*
|
|
4411
|
+
*
|
|
4412
|
+
* - **Layer 1**: Boot-time referential equality (corroborated by Layer 2).
|
|
4413
|
+
* Best-effort; misses attackers who inject before SDK load.
|
|
4414
|
+
* - **Layer 2**: Fresh-iframe cross-realm `toString` comparison. Best-effort;
|
|
4415
|
+
* produces false positives in browser-level instrumentation contexts (CriOS,
|
|
4416
|
+
* extensions). The page-vs-iframe disagreement case is gated on iframe
|
|
4417
|
+
* trustworthiness to mitigate this.
|
|
4418
|
+
* - **Layer 3**: Customer-provided token validation (only runs when a token
|
|
4419
|
+
* is supplied). **This is the strong defense** — see `captureMediaIntegrity`.
|
|
4420
|
+
*
|
|
4421
|
+
* Returns clean immediately if `enabled` is not true.
|
|
4352
4422
|
*/
|
|
4353
|
-
function checkGetUserMediaIntegrity(
|
|
4423
|
+
function checkGetUserMediaIntegrity(options) {
|
|
4424
|
+
if (options === void 0) {
|
|
4425
|
+
options = {};
|
|
4426
|
+
}
|
|
4427
|
+
if (!options.enabled) {
|
|
4428
|
+
return {
|
|
4429
|
+
tampered: false,
|
|
4430
|
+
details: []
|
|
4431
|
+
};
|
|
4432
|
+
}
|
|
4354
4433
|
var allDetails = [];
|
|
4355
|
-
var l1 = checkLayer1();
|
|
4356
|
-
allDetails.push.apply(allDetails, l1.details);
|
|
4357
4434
|
var l2 = checkLayer2();
|
|
4435
|
+
var l1 = checkLayer1(l2);
|
|
4436
|
+
allDetails.push.apply(allDetails, l1.details);
|
|
4358
4437
|
allDetails.push.apply(allDetails, l2.details);
|
|
4359
|
-
var l3 = checkLayer3(token);
|
|
4438
|
+
var l3 = checkLayer3(options.token);
|
|
4360
4439
|
allDetails.push.apply(allDetails, l3.details);
|
|
4361
4440
|
var tampered = l1.tampered || l2.tampered || l3.tampered;
|
|
4362
4441
|
if (tampered) {
|
|
@@ -4370,12 +4449,26 @@ function checkGetUserMediaIntegrity(token) {
|
|
|
4370
4449
|
};
|
|
4371
4450
|
}
|
|
4372
4451
|
/**
|
|
4373
|
-
* Lightweight pre-call guard
|
|
4374
|
-
* Returns `
|
|
4452
|
+
* Lightweight pre-call guard. Returns `true` if tampering is detected.
|
|
4453
|
+
* Returns `false` immediately when not enabled.
|
|
4454
|
+
*
|
|
4455
|
+
* Runs Layer 1 (corroborated by a cached Layer 2 verdict) and Layer 3.
|
|
4456
|
+
* The full check at mount time (`checkGetUserMediaIntegrity`) re-runs Layer 2
|
|
4457
|
+
* fresh for completeness; this guard uses the cache so per-call cost is low.
|
|
4458
|
+
*
|
|
4459
|
+
* For strong tamper resistance, customers should pass a token captured via
|
|
4460
|
+
* `captureMediaIntegrity` — Layer 1 is best-effort and can produce false
|
|
4461
|
+
* positives against legitimate post-init shims (`webrtc-adapter`, polyfills,
|
|
4462
|
+
* browser extensions).
|
|
4375
4463
|
*/
|
|
4376
|
-
function guardGetUserMedia(
|
|
4377
|
-
|
|
4378
|
-
|
|
4464
|
+
function guardGetUserMedia(options) {
|
|
4465
|
+
if (options === void 0) {
|
|
4466
|
+
options = {};
|
|
4467
|
+
}
|
|
4468
|
+
if (!options.enabled) return false;
|
|
4469
|
+
var l2 = getCachedLayer2Verdict();
|
|
4470
|
+
var l1 = checkLayer1(l2);
|
|
4471
|
+
var l3 = checkLayer3(options.token);
|
|
4379
4472
|
var tampered = l1.tampered || l3.tampered;
|
|
4380
4473
|
if (tampered) {
|
|
4381
4474
|
error("".concat(LOG_TAG$2, " guard detected tampering:"), __spreadArray(__spreadArray([], l1.details, true), l3.details, true));
|
|
@@ -4385,16 +4478,19 @@ function guardGetUserMedia(token) {
|
|
|
4385
4478
|
|
|
4386
4479
|
var LOG_TAG$1 = 'camera:Camera';
|
|
4387
4480
|
function listAvailableCameras(facingMode_1) {
|
|
4388
|
-
return __awaiter(this, arguments, void 0, function (facingMode, requestMicAccess,
|
|
4481
|
+
return __awaiter(this, arguments, void 0, function (facingMode, requestMicAccess, tamper) {
|
|
4389
4482
|
var cameraEnumerationStream, allDevices, allowedVideoDevices;
|
|
4390
4483
|
if (requestMicAccess === void 0) {
|
|
4391
4484
|
requestMicAccess = false;
|
|
4392
4485
|
}
|
|
4486
|
+
if (tamper === void 0) {
|
|
4487
|
+
tamper = {};
|
|
4488
|
+
}
|
|
4393
4489
|
return __generator(this, function (_a) {
|
|
4394
4490
|
switch (_a.label) {
|
|
4395
4491
|
case 0:
|
|
4396
4492
|
// The first thing we need to do is call getUserMedia() so that the subsequent call to enumerateDevices() works.
|
|
4397
|
-
if (guardGetUserMedia(
|
|
4493
|
+
if (guardGetUserMedia(tamper)) {
|
|
4398
4494
|
throw new Error('getUserMedia tampering detected');
|
|
4399
4495
|
}
|
|
4400
4496
|
return [4 /*yield*/, navigator.mediaDevices.getUserMedia({
|
|
@@ -5732,7 +5828,10 @@ var createCameraStore = function createCameraStore(config) {
|
|
|
5732
5828
|
case 0:
|
|
5733
5829
|
debug("".concat(LOG_TAG, " requestCameraAccess"), new Error().stack);
|
|
5734
5830
|
_a = get(), videoRef = _a.videoRef, releaseCameraAccess = _a.releaseCameraAccess, preferFrontFacingCamera = _a.preferFrontFacingCamera, preferIphoneContinuityCamera = _a.preferIphoneContinuityCamera, iphoneContinuityCameraDenied = _a.iphoneContinuityCameraDenied, enableTamperDetection = _a.enableTamperDetection, mediaIntegrityToken = _a.mediaIntegrityToken;
|
|
5735
|
-
if (
|
|
5831
|
+
if (guardGetUserMedia({
|
|
5832
|
+
enabled: enableTamperDetection,
|
|
5833
|
+
token: mediaIntegrityToken
|
|
5834
|
+
})) {
|
|
5736
5835
|
set({
|
|
5737
5836
|
cameraTamperingDetected: true
|
|
5738
5837
|
});
|
|
@@ -5742,7 +5841,10 @@ var createCameraStore = function createCameraStore(config) {
|
|
|
5742
5841
|
_f.label = 1;
|
|
5743
5842
|
case 1:
|
|
5744
5843
|
_f.trys.push([1, 11,, 12]);
|
|
5745
|
-
return [4 /*yield*/, listAvailableCameras(undefined, false,
|
|
5844
|
+
return [4 /*yield*/, listAvailableCameras(undefined, false, {
|
|
5845
|
+
enabled: enableTamperDetection,
|
|
5846
|
+
token: mediaIntegrityToken
|
|
5847
|
+
})];
|
|
5746
5848
|
case 2:
|
|
5747
5849
|
availableCameras = _f.sent();
|
|
5748
5850
|
selectedCamera = void 0;
|
|
@@ -5954,7 +6056,10 @@ var createCameraStore = function createCameraStore(config) {
|
|
|
5954
6056
|
switch (_a.label) {
|
|
5955
6057
|
case 0:
|
|
5956
6058
|
get().releaseMicrophoneAccess();
|
|
5957
|
-
if (
|
|
6059
|
+
if (guardGetUserMedia({
|
|
6060
|
+
enabled: get().enableTamperDetection,
|
|
6061
|
+
token: get().mediaIntegrityToken
|
|
6062
|
+
})) {
|
|
5958
6063
|
set({
|
|
5959
6064
|
cameraTamperingDetected: true
|
|
5960
6065
|
});
|
|
@@ -6078,8 +6183,10 @@ function CameraStoreProvider(_a) {
|
|
|
6078
6183
|
}));
|
|
6079
6184
|
React.useEffect(function () {
|
|
6080
6185
|
var _a;
|
|
6081
|
-
|
|
6082
|
-
|
|
6186
|
+
var result = checkGetUserMediaIntegrity({
|
|
6187
|
+
enabled: enableTamperDetection,
|
|
6188
|
+
token: mediaIntegrityToken
|
|
6189
|
+
});
|
|
6083
6190
|
if (result.tampered) {
|
|
6084
6191
|
(_a = store.current) === null || _a === void 0 ? void 0 : _a.setState({
|
|
6085
6192
|
cameraTamperingDetected: true
|