@richard.fadiora/liveness-detection 5.0.4 → 5.1.0
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/README.md +19 -5
- package/dist/{LivenessCheck-CjVP-81C.cjs → LivenessCheck-6oh9vnb0.cjs} +6 -6
- package/dist/{LivenessCheck-uEzmlOY8.js → LivenessCheck-CtndKzVw.js} +654 -649
- package/dist/angular/README.md +19 -5
- package/dist/angular/fesm2022/richard.fadiora-liveness-detection.mjs +41 -13
- package/dist/angular/fesm2022/richard.fadiora-liveness-detection.mjs.map +1 -1
- package/dist/angular/types/richard.fadiora-liveness-detection.d.ts +5 -0
- package/dist/core/LivenessEngine.d.ts +5 -0
- package/dist/core/LivenessEngine.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +2 -2
- package/dist/react.cjs +1 -1
- package/dist/react.js +1 -1
- package/package.json +1 -1
package/dist/angular/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# Liveness Detection SDK v5.0
|
|
1
|
+
# Liveness Detection SDK v5.1.0
|
|
2
2
|
|
|
3
|
-
A high-security, cross-framework **Liveness Detection SDK** designed for financial services. v5.0
|
|
3
|
+
A high-security, cross-framework **Liveness Detection SDK** designed for financial services. v5.1.0 introduces **Temporal Identity Locking** to prevent identity switching during the verification process.
|
|
4
4
|
|
|
5
|
-
## 🔒 New Security Protocols (v5.0
|
|
5
|
+
## 🔒 New Security Protocols (v5.1.0)
|
|
6
6
|
|
|
7
7
|
This version introduces a "Zero-Trust" frontend architecture:
|
|
8
8
|
|
|
@@ -118,7 +118,7 @@ TypeScript
|
|
|
118
118
|
|
|
119
119
|
* * *
|
|
120
120
|
|
|
121
|
-
## 🚨 Updated Error Reference (
|
|
121
|
+
## 🚨 Updated Error Reference (v5.1.0)
|
|
122
122
|
|
|
123
123
|
The following codes are now emitted by the frontend engine **instantly**, without hitting the backend:
|
|
124
124
|
|
|
@@ -129,6 +129,20 @@ The following codes are now emitted by the frontend engine **instantly**, withou
|
|
|
129
129
|
| Security violation: Identity mismatch. | Biometric ratios shifted significantly mid-session. | Prevents mid-stream person-swapping. |
|
|
130
130
|
| Another session is active. | User has the verification open in another tab. | Prevents multi-device brute forcing. |
|
|
131
131
|
|
|
132
|
+
* * *
|
|
133
|
+
### ⚠️ Security Warnings & Temporary Interruption
|
|
134
|
+
|
|
135
|
+
Version 5.0.2 implements a non-fatal warning system for non-critical security events (e.g., fleeting obscuration).
|
|
136
|
+
|
|
137
|
+
* **Temporary Interruption**: If a security violation occurs (e.g., face obscured), the `LivenessEngine` will pause detection for **2 seconds** to allow the user to adjust their position.
|
|
138
|
+
|
|
139
|
+
* **Warning Counter**: The engine tracks these events using `warningCount`. If the violations exceed `MAX_WARNINGS` (default: 3), the session will trigger a `failInstantly` event.
|
|
140
|
+
|
|
141
|
+
* **State Feedback**: During the 2-second pause, the `errorMsg` property in `LivenessState` will be populated with a temporary notification (e.g., _"Please ensure both ears are fully visible. (Warning 1/3)"_).
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
**Best Practice:** Always subscribe to `onStateChange` in your UI layer to ensure your user-facing components react to the `errorMsg` text.
|
|
145
|
+
|
|
132
146
|
* * *
|
|
133
147
|
|
|
134
148
|
## 🏗️ Architectural Flow
|
|
@@ -148,7 +162,7 @@ These images are cropped to **224x224px** focusing on the face, making them opti
|
|
|
148
162
|
|
|
149
163
|
* * *
|
|
150
164
|
|
|
151
|
-
## 🔧 Integration Notes for v5.0
|
|
165
|
+
## 🔧 Integration Notes for v5.1.0
|
|
152
166
|
|
|
153
167
|
* **WASM Path**: Ensure your server allows cross-origin requests for the MediaPipe `.wasm` files hosted on JSDelivr.
|
|
154
168
|
|
|
@@ -16,6 +16,10 @@ class LivenessEngine {
|
|
|
16
16
|
timerId = null;
|
|
17
17
|
requestId = null;
|
|
18
18
|
heartbeatId = null;
|
|
19
|
+
warningCount = 0;
|
|
20
|
+
MAX_WARNINGS = 3;
|
|
21
|
+
lastWarningMsg = "";
|
|
22
|
+
isDetectionPaused = false;
|
|
19
23
|
// --- NEW SECURITY TRACKERS ---
|
|
20
24
|
anchorRatios = null;
|
|
21
25
|
lastNosePos = null;
|
|
@@ -103,19 +107,40 @@ class LivenessEngine {
|
|
|
103
107
|
return true;
|
|
104
108
|
}
|
|
105
109
|
const diff = Math.abs(this.anchorRatios - currentRatio) / this.anchorRatios;
|
|
106
|
-
return diff < 0.
|
|
110
|
+
return diff < 0.70; // 70% tolerance for head tilt
|
|
107
111
|
}
|
|
108
112
|
checkMovement(landmarks) {
|
|
109
113
|
const nose = { x: landmarks[1].x, y: landmarks[1].y };
|
|
110
114
|
if (this.lastNosePos) {
|
|
111
115
|
const dist = Math.sqrt(Math.pow(nose.x - this.lastNosePos.x, 2) +
|
|
112
116
|
Math.pow(nose.y - this.lastNosePos.y, 2));
|
|
113
|
-
if (dist > 0.
|
|
117
|
+
if (dist > 0.5)
|
|
114
118
|
return false; // Sudden teleportation
|
|
115
119
|
}
|
|
116
120
|
this.lastNosePos = nose;
|
|
117
121
|
return true;
|
|
118
122
|
}
|
|
123
|
+
handleViolation(reason) {
|
|
124
|
+
this.warningCount++;
|
|
125
|
+
if (this.warningCount >= this.MAX_WARNINGS) {
|
|
126
|
+
this.failInstantly(reason);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
this.isDetectionPaused = true; // Set BEFORE cancelling
|
|
130
|
+
if (this.requestId) {
|
|
131
|
+
cancelAnimationFrame(this.requestId);
|
|
132
|
+
this.requestId = null;
|
|
133
|
+
}
|
|
134
|
+
this.updateState({ errorMsg: `${reason} (Warning ${this.warningCount}/${this.MAX_WARNINGS})` });
|
|
135
|
+
setTimeout(() => {
|
|
136
|
+
if (this.state.status !== "capturing")
|
|
137
|
+
return;
|
|
138
|
+
this.isDetectionPaused = false;
|
|
139
|
+
this.updateState({ errorMsg: "" });
|
|
140
|
+
this.detectLoop();
|
|
141
|
+
}, 2000); // Give user 2 seconds to adjust
|
|
142
|
+
}
|
|
143
|
+
}
|
|
119
144
|
failInstantly(reason) {
|
|
120
145
|
this.stop();
|
|
121
146
|
this.updateState({ status: "error", errorMsg: reason, isStepTransitioning: false });
|
|
@@ -161,6 +186,8 @@ class LivenessEngine {
|
|
|
161
186
|
this.lastNosePos = null;
|
|
162
187
|
this.consecutiveMissingFrames = 0;
|
|
163
188
|
this.stabilityFrames = 0;
|
|
189
|
+
this.warningCount = 0;
|
|
190
|
+
this.isDetectionPaused = false;
|
|
164
191
|
this.generateSequence();
|
|
165
192
|
this.updateState({
|
|
166
193
|
status: "ready",
|
|
@@ -177,7 +204,7 @@ class LivenessEngine {
|
|
|
177
204
|
}
|
|
178
205
|
generateSequence() {
|
|
179
206
|
const seq = [...this.CHALLENGE_POOL].sort(() => 0.5 - Math.random()).slice(0, 3);
|
|
180
|
-
this.
|
|
207
|
+
this.updateState({ sequence: seq });
|
|
181
208
|
return seq;
|
|
182
209
|
}
|
|
183
210
|
startTimer() {
|
|
@@ -194,7 +221,7 @@ class LivenessEngine {
|
|
|
194
221
|
}, 1000);
|
|
195
222
|
}
|
|
196
223
|
detectLoop = () => {
|
|
197
|
-
if (this.state.status !== "capturing" || !this.webcam || !this.models.face)
|
|
224
|
+
if (this.state.status !== "capturing" || !this.webcam || !this.models.face || this.isDetectionPaused)
|
|
198
225
|
return;
|
|
199
226
|
const now = performance.now();
|
|
200
227
|
try {
|
|
@@ -203,7 +230,7 @@ class LivenessEngine {
|
|
|
203
230
|
// 1. Multi-Face Security
|
|
204
231
|
if (faceRes.faceLandmarks && faceRes.faceLandmarks.length > 1) {
|
|
205
232
|
console.warn("[LivenessEngine] Security Alert: Multiple faces detected!");
|
|
206
|
-
this.
|
|
233
|
+
this.handleViolation("Multiple faces detected. Please ensure only one person is in frame.");
|
|
207
234
|
return; // CRITICAL: Stop execution here
|
|
208
235
|
}
|
|
209
236
|
const landmarks = faceRes.faceLandmarks?.[0];
|
|
@@ -211,7 +238,7 @@ class LivenessEngine {
|
|
|
211
238
|
if (!landmarks) {
|
|
212
239
|
this.consecutiveMissingFrames++;
|
|
213
240
|
if (this.consecutiveMissingFrames > this.MAX_GAP) {
|
|
214
|
-
return this.
|
|
241
|
+
return this.handleViolation("Face lost. Session reset.");
|
|
215
242
|
}
|
|
216
243
|
}
|
|
217
244
|
else {
|
|
@@ -225,10 +252,12 @@ class LivenessEngine {
|
|
|
225
252
|
else {
|
|
226
253
|
// Only perform the security check AFTER the anchor is established
|
|
227
254
|
if (!this.verifyIdentity(landmarks) || !this.checkMovement(landmarks)) {
|
|
228
|
-
this.
|
|
255
|
+
this.handleViolation("Security violation: Identity mismatch.");
|
|
229
256
|
return;
|
|
230
257
|
}
|
|
231
258
|
}
|
|
259
|
+
if (this.state.errorMsg)
|
|
260
|
+
this.updateState({ errorMsg: "" });
|
|
232
261
|
// 3. Challenge Logic
|
|
233
262
|
const currentChallenge = this.state.sequence[this.currentStepRef];
|
|
234
263
|
const handRes = this.models.hand?.detectForVideo(this.webcam, now);
|
|
@@ -290,9 +319,9 @@ class LivenessEngine {
|
|
|
290
319
|
case "Smile":
|
|
291
320
|
return (lms[291].x - lms[61].x) > this.config.smileThreshold;
|
|
292
321
|
case "Blink":
|
|
293
|
-
const
|
|
294
|
-
const
|
|
295
|
-
return ((
|
|
322
|
+
const leftEye = Math.abs(lms[159].y - lms[145].y);
|
|
323
|
+
const rightEye = Math.abs(lms[386].y - lms[374].y);
|
|
324
|
+
return ((leftEye + rightEye) / 2) < this.config.blinkThreshold;
|
|
296
325
|
case "Turn_Head":
|
|
297
326
|
const yaw = (lms[1].x - lms[33].x) / (lms[263].x - lms[33].x);
|
|
298
327
|
return yaw < this.config.minturnHeadThreshold || yaw > this.config.maxturnHeadThreshold;
|
|
@@ -308,7 +337,7 @@ class LivenessEngine {
|
|
|
308
337
|
const blobs = [];
|
|
309
338
|
let finalBase64 = "";
|
|
310
339
|
for (let i = 0; i < 5; i++) {
|
|
311
|
-
if (!this.webcam)
|
|
340
|
+
if (!this.webcam || !this.models.face)
|
|
312
341
|
break;
|
|
313
342
|
const faceRes = this.models.face?.detectForVideo(this.webcam, performance.now());
|
|
314
343
|
if (faceRes?.faceLandmarks?.[0]) {
|
|
@@ -339,7 +368,6 @@ class LivenessEngine {
|
|
|
339
368
|
}
|
|
340
369
|
}
|
|
341
370
|
async getFaceCrop(video, landmarks) {
|
|
342
|
-
const ctx = this.offscreenCanvas.getContext("2d");
|
|
343
371
|
const xs = landmarks.map(l => l.x * video.videoWidth);
|
|
344
372
|
const ys = landmarks.map(l => l.y * video.videoHeight);
|
|
345
373
|
const minX = Math.min(...xs);
|
|
@@ -353,10 +381,10 @@ class LivenessEngine {
|
|
|
353
381
|
const sourceY = Math.max(0, minY - margin);
|
|
354
382
|
const sourceW = Math.min(video.videoWidth - sourceX, width + margin * 2);
|
|
355
383
|
const sourceH = Math.min(video.videoHeight - sourceY, height + margin * 2);
|
|
384
|
+
const ctx = this.offscreenCanvas.getContext("2d");
|
|
356
385
|
try {
|
|
357
386
|
// 2. Extract the bitmap (This bypasses many canvas-tainting triggers)
|
|
358
387
|
const bitmap = await createImageBitmap(video, sourceX, sourceY, sourceW, sourceH);
|
|
359
|
-
const ctx = this.offscreenCanvas.getContext("2d");
|
|
360
388
|
ctx.clearRect(0, 0, 224, 224);
|
|
361
389
|
// 3. Draw the clean bitmap to the offscreen canvas
|
|
362
390
|
ctx.drawImage(bitmap, 0, 0, 224, 224);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"richard.fadiora-liveness-detection.mjs","sources":["../../../src/core/LivenessEngine.ts","../../../src/angular/liveness.service.ts","../../../src/angular/liveness.component.ts","../../../src/angular/liveness.component.html","../../../src/api.ts","../../../src/richard.fadiora-liveness-detection.ts"],"sourcesContent":["// src/core/LivenessEngine.ts\r\nimport { FaceLandmarker, HandLandmarker, FilesetResolver, NormalizedLandmark } from \"@mediapipe/tasks-vision\";\r\n\r\nexport type Challenge = \"Smile\" | \"Blink\" | \"Turn_Head\" | \"Thumbs_Up\";\r\n\r\nexport interface ChallengeSnapshot {\r\n challenge: Challenge;\r\n image: string; // Base64 data URL\r\n timestamp: number;\r\n}\r\n\r\nexport interface LivenessSDKResult {\r\n success: boolean;\r\n image?: string;\r\n reason?: string;\r\n skinConfidence?: number;\r\n snapshots?: ChallengeSnapshot[];\r\n}\r\n\r\nexport interface LivenessState {\r\n status: \"loading\" | \"ready\" | \"capturing\" | \"verifying\" | \"success\" | \"error\" | \"expired\";\r\n sequence: Challenge[];\r\n currentStep: number;\r\n timeLeft: number;\r\n isStepTransitioning: boolean;\r\n errorMsg: string;\r\n snapshots: ChallengeSnapshot[];\r\n}\r\n\r\nexport interface LivenessEngineConfig {\r\n apiUrl: string;\r\n duration?: number;\r\n smileThreshold?: number;\r\n blinkThreshold?: number;\r\n minturnHeadThreshold?: number;\r\n maxturnHeadThreshold?: number;\r\n onStateChange?: (state: LivenessState) => void;\r\n onComplete?: (result: LivenessSDKResult) => void;\r\n onError?: (error: LivenessSDKResult) => void;\r\n}\r\n\r\nexport class LivenessEngine {\r\n private config: Required<LivenessEngineConfig>;\r\n private models: { face: FaceLandmarker | null; hand: HandLandmarker | null } = { face: null, hand: null };\r\n private webcam: HTMLVideoElement | null = null;\r\n private state: LivenessState;\r\n \r\n private currentStepRef = 0;\r\n private isStepTransitioningRef = false;\r\n private timerId: ReturnType<typeof setInterval> | null = null;\r\n private requestId: number | null = null;\r\n private heartbeatId: ReturnType<typeof setInterval> | null = null;\r\n \r\n // --- NEW SECURITY TRACKERS ---\r\n private anchorRatios: number | null = null;\r\n private lastNosePos: { x: number; y: number } | null = null;\r\n private consecutiveMissingFrames = 0;\r\n private readonly MAX_GAP = 15; // ~250ms buffer\r\n private readonly LIVENESS_LOCK_KEY = \"liveness_active_session\";\r\n private stabilityFrames = 0;\r\n private readonly REQUIRED_STABILITY = 10; // Wait for ~10 clear frames before locking\r\n \r\n private offscreenCanvas = document.createElement(\"canvas\");\r\n private CHALLENGE_POOL: Challenge[] = [\"Smile\", \"Blink\", \"Turn_Head\", \"Thumbs_Up\"];\r\n\r\n constructor(config: LivenessEngineConfig) {\r\n this.config = {\r\n apiUrl: config.apiUrl,\r\n duration: config.duration ?? 60,\r\n smileThreshold: config.smileThreshold ?? 0.2,\r\n blinkThreshold: config.blinkThreshold ?? 0.012,\r\n minturnHeadThreshold: config.minturnHeadThreshold ?? 0.15,\r\n maxturnHeadThreshold: config.maxturnHeadThreshold ?? 0.85,\r\n onStateChange: config.onStateChange || (() => {}),\r\n onComplete: config.onComplete || (() => {}),\r\n onError: config.onError || (() => {}),\r\n };\r\n\r\n this.state = {\r\n status: \"loading\",\r\n sequence: [],\r\n currentStep: 0,\r\n timeLeft: this.config.duration,\r\n isStepTransitioning: false,\r\n errorMsg: \"\",\r\n snapshots: [],\r\n };\r\n \r\n this.offscreenCanvas.width = 224;\r\n this.offscreenCanvas.height = 224;\r\n }\r\n\r\n /**\r\n * Phase 1: Load AI Assets (Call this immediately on mount)\r\n */\r\n public async loadModels() {\r\n console.log(\"[LivenessEngine] Loading AI Models...\");\r\n try {\r\n const vision = await FilesetResolver.forVisionTasks(\r\n \"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.3/wasm\"\r\n );\r\n\r\n this.models.face = await FaceLandmarker.createFromOptions(vision, {\r\n baseOptions: {\r\n modelAssetPath: \"https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task\",\r\n delegate: \"GPU\",\r\n },\r\n outputFaceBlendshapes: true,\r\n runningMode: \"VIDEO\",\r\n });\r\n\r\n this.models.hand = await HandLandmarker.createFromOptions(vision, {\r\n baseOptions: {\r\n modelAssetPath: \"https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task\",\r\n delegate: \"GPU\",\r\n },\r\n runningMode: \"VIDEO\",\r\n numHands: 1,\r\n });\r\n\r\n this.generateSequence();\r\n // Stay in 'loading' or move to a 'ready_to_mount' status if you prefer\r\n // For now, we move to ready to signal the UI can show the camera\r\n this.updateState({ status: \"ready\" });\r\n console.log(\"[LivenessEngine] Models Loaded.\");\r\n } catch (err) {\r\n console.error(\"[LivenessEngine] Init Error:\", err);\r\n this.updateState({ status: \"error\", errorMsg: \"Failed to load security assets.\" });\r\n }\r\n }\r\n\r\n /**\r\n * Phase 2: Attach Video (Call this once the Webcam is in the DOM)\r\n */\r\n public attachVideo = (video: HTMLVideoElement) => {\r\n video.setAttribute('crossorigin', 'anonymous');\r\n this.webcam = video;\r\n console.log(\"[LivenessEngine] Video stream attached.\");\r\n };\r\n\r\n // --- NEW SECURITY METHODS ---\r\n\r\n private verifyIdentity(landmarks: NormalizedLandmark[]): boolean {\r\n const eyeDist = Math.sqrt(\r\n Math.pow(landmarks[33].x - landmarks[263].x, 2) + \r\n Math.pow(landmarks[33].y - landmarks[263].y, 2)\r\n );\r\n const noseToMouth = Math.abs(landmarks[1].y - landmarks[13].y);\r\n const currentRatio = eyeDist / (noseToMouth || 1);\r\n\r\n if (this.anchorRatios === null) {\r\n this.anchorRatios = currentRatio;\r\n return true;\r\n }\r\n\r\n const diff = Math.abs(this.anchorRatios - currentRatio) / this.anchorRatios;\r\n return diff < 0.50; // 50% tolerance for head tilt\r\n }\r\n\r\n private checkMovement(landmarks: NormalizedLandmark[]): boolean {\r\n const nose = { x: landmarks[1].x, y: landmarks[1].y };\r\n if (this.lastNosePos) {\r\n const dist = Math.sqrt(\r\n Math.pow(nose.x - this.lastNosePos.x, 2) + \r\n Math.pow(nose.y - this.lastNosePos.y, 2)\r\n );\r\n if (dist > 0.3) return false; // Sudden teleportation\r\n }\r\n this.lastNosePos = nose;\r\n return true;\r\n }\r\n\r\n private failInstantly(reason: string) {\r\n this.stop();\r\n this.updateState({ status: \"error\", errorMsg: reason, isStepTransitioning: false });\r\n this.config.onError({ success: false, reason });\r\n }\r\n\r\n public start = () => {\r\n // Multi-tab Prevention\r\n const active = localStorage.getItem(this.LIVENESS_LOCK_KEY);\r\n if (active && Date.now() - parseInt(active) < 5000) {\r\n this.failInstantly(\"Another session is active.\");\r\n return;\r\n }\r\n\r\n this.heartbeatId = setInterval(() => {\r\n localStorage.setItem(this.LIVENESS_LOCK_KEY, Date.now().toString());\r\n }, 1000);\r\n\r\n if (this.state.status !== \"ready\" || !this.webcam) {\r\n console.warn(\"[LivenessEngine] Engine not ready or video missing.\");\r\n return;\r\n }\r\n\r\n console.log(\"[LivenessEngine] Session Starting...\");\r\n this.state.status = \"capturing\"; // Sync internal status immediately\r\n this.updateState({ status: \"capturing\" });\r\n this.startTimer();\r\n this.detectLoop();\r\n };\r\n\r\n public stop = () => {\r\n if (this.timerId) clearInterval(this.timerId);\r\n if (this.heartbeatId) clearInterval(this.heartbeatId);\r\n if (this.requestId) cancelAnimationFrame(this.requestId);\r\n localStorage.removeItem(this.LIVENESS_LOCK_KEY);\r\n\r\n this.timerId = null;\r\n this.heartbeatId = null;\r\n this.requestId = null;\r\n };\r\n\r\n public reset = () => {\r\n this.stop();\r\n this.currentStepRef = 0;\r\n this.isStepTransitioningRef = false;\r\n this.anchorRatios = null;\r\n this.lastNosePos = null;\r\n this.consecutiveMissingFrames = 0;\r\n this.stabilityFrames = 0;\r\n this.generateSequence();\r\n this.updateState({\r\n status: \"ready\",\r\n currentStep: 0,\r\n timeLeft: this.config.duration,\r\n isStepTransitioning: false,\r\n errorMsg: \"\",\r\n snapshots: [],\r\n });\r\n};\r\n\r\n private updateState(newState: Partial<LivenessState>) {\r\n this.state = { ...this.state, ...newState };\r\n this.config.onStateChange(this.state);\r\n }\r\n\r\n private generateSequence(): Challenge[] {\r\n const seq = [...this.CHALLENGE_POOL].sort(() => 0.5 - Math.random()).slice(0, 3);\r\n this.state.sequence = seq;\r\n return seq;\r\n }\r\n\r\n private startTimer() {\r\n if (this.timerId) clearInterval(this.timerId);\r\n this.timerId = setInterval(() => {\r\n if (this.state.timeLeft > 0) {\r\n this.updateState({ timeLeft: this.state.timeLeft - 1 });\r\n } else {\r\n this.stop();\r\n this.updateState({ status: \"expired\" });\r\n }\r\n }, 1000);\r\n }\r\n\r\n private detectLoop = () => {\r\n if (this.state.status !== \"capturing\" || !this.webcam || !this.models.face) return;\r\n\r\n const now = performance.now();\r\n try {\r\n const faceRes = this.models.face.detectForVideo(this.webcam, now);\r\n \r\n // --- NEW SECURITY CHECKS ---\r\n // 1. Multi-Face Security\r\n if (faceRes.faceLandmarks && faceRes.faceLandmarks.length > 1) {\r\n console.warn(\"[LivenessEngine] Security Alert: Multiple faces detected!\");\r\n this.failInstantly(\"Multiple faces detected. Please ensure only one person is in frame.\");\r\n return; // CRITICAL: Stop execution here\r\n }\r\n \r\n const landmarks = faceRes.faceLandmarks?.[0];\r\n\r\n // 2. Continuity & Identity Security\r\n if (!landmarks) {\r\n this.consecutiveMissingFrames++;\r\n if (this.consecutiveMissingFrames > this.MAX_GAP) {\r\n return this.failInstantly(\"Face lost. Session reset.\");\r\n }\r\n } else {\r\n this.consecutiveMissingFrames = 0;\r\n\r\n if (this.anchorRatios === null) {\r\n this.stabilityFrames++;\r\n if (this.stabilityFrames >= this.REQUIRED_STABILITY) {\r\n this.verifyIdentity(landmarks); // This sets the anchor for the first time\r\n }\r\n } else {\r\n // Only perform the security check AFTER the anchor is established\r\n if (!this.verifyIdentity(landmarks) || !this.checkMovement(landmarks)) {\r\n this.failInstantly(\"Security violation: Identity mismatch.\");\r\n return;\r\n }\r\n }\r\n\r\n // 3. Challenge Logic\r\n const currentChallenge = this.state.sequence[this.currentStepRef];\r\n const handRes = this.models.hand?.detectForVideo(this.webcam, now);\r\n\r\n if (this.checkAction(faceRes, handRes, currentChallenge)) {\r\n this.handleStepSuccess(landmarks); // Pass landmarks to capture\r\n return; \r\n }\r\n }\r\n\r\n this.requestId = requestAnimationFrame(this.detectLoop);\r\n\r\n } catch (err) {\r\n console.error(\"[LivenessEngine] Loop detection error:\", err);\r\n this.requestId = requestAnimationFrame(this.detectLoop);\r\n }\r\n\r\n };\r\n\r\n private async handleStepSuccess(landmarks: NormalizedLandmark[]) {\r\n if (this.isStepTransitioningRef) return;\r\n \r\n this.isStepTransitioningRef = true;\r\n\r\n // Capture Snapshot\r\n const canvas = await this.getFaceCrop(this.webcam!, landmarks);\r\n const snapshot: ChallengeSnapshot = {\r\n challenge: this.state.sequence[this.currentStepRef],\r\n image: canvas.toDataURL(\"image/jpeg\", 0.7),\r\n timestamp: Date.now()\r\n };\r\n\r\n const updatedSnapshots = [...this.state.snapshots, snapshot];\r\n\r\n this.updateState({ isStepTransitioning: true, snapshots: updatedSnapshots });\r\n\r\n setTimeout(() => {\r\n // Check if engine was stopped during the timeout\r\n if (this.state.status !== \"capturing\") return;\r\n\r\n if (this.currentStepRef < this.state.sequence.length - 1) {\r\n this.currentStepRef++;\r\n this.isStepTransitioningRef = false;\r\n this.updateState({\r\n currentStep: this.currentStepRef,\r\n isStepTransitioning: false,\r\n snapshots: updatedSnapshots,\r\n });\r\n this.requestId = requestAnimationFrame(this.detectLoop);\r\n } else {\r\n this.updateState({ snapshots: updatedSnapshots });\r\n this.sendFinalProof();\r\n }\r\n }, 1500);\r\n }\r\n\r\n private checkAction(faceRes: any, handRes: any, challenge: Challenge): boolean {\r\n if (this.isStepTransitioningRef) return false;\r\n\r\n if (challenge === \"Thumbs_Up\" && handRes?.landmarks?.length > 0) {\r\n const l = handRes.landmarks[0];\r\n return l[4].y < l[2].y && [8, 12, 16, 20].every(i => l[i].y > l[i - 2].y);\r\n }\r\n\r\n if (faceRes?.faceLandmarks?.length > 0) {\r\n const lms: NormalizedLandmark[] = faceRes.faceLandmarks[0];\r\n switch (challenge) {\r\n case \"Smile\":\r\n return (lms[291].x - lms[61].x) > this.config.smileThreshold;\r\n case \"Blink\":\r\n const leftEar = Math.abs(lms[159].y - lms[145].y);\r\n const rightEar = Math.abs(lms[386].y - lms[374].y);\r\n return ((leftEar + rightEar) / 2) < this.config.blinkThreshold;\r\n case \"Turn_Head\":\r\n const yaw = (lms[1].x - lms[33].x) / (lms[263].x - lms[33].x);\r\n return yaw < this.config.minturnHeadThreshold || yaw > this.config.maxturnHeadThreshold;\r\n default: return false;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n private async sendFinalProof() {\r\n this.stop();\r\n this.updateState({ status: \"verifying\" });\r\n\r\n try {\r\n const blobs: Blob[] = [];\r\n let finalBase64 = \"\";\r\n\r\n for (let i = 0; i < 5; i++) {\r\n if (!this.webcam) break;\r\n const faceRes = this.models.face?.detectForVideo(this.webcam, performance.now());\r\n if (faceRes?.faceLandmarks?.[0]) {\r\n const canvas = await this.getFaceCrop(this.webcam, faceRes.faceLandmarks[0]);\r\n const blob = await new Promise<Blob | null>(res => canvas.toBlob(res, \"image/jpeg\", 0.9));\r\n if (blob) blobs.push(blob);\r\n if (i === 4) finalBase64 = canvas.toDataURL(\"image/jpeg\");\r\n }\r\n await new Promise(r => setTimeout(r, 100));\r\n }\r\n\r\n const { verifyLiveness } = await import(\"../api\");\r\n const result = await verifyLiveness(this.config.apiUrl, blobs, this.state.sequence);\r\n\r\n if (result.is_live) {\r\n this.updateState({ status: \"success\" });\r\n this.config.onComplete({ success: true, image: finalBase64, skinConfidence: result.skin_confidence });\r\n } else {\r\n const reason = result.reason || \"Liveness check failed\";\r\n this.updateState({ status: \"error\", errorMsg: reason });\r\n this.config.onError({ success: false, reason });\r\n }\r\n } catch (err) {\r\n this.updateState({ status: \"error\", errorMsg: \"Verification failed.\" });\r\n this.config.onError({ success: false, reason: \"Network error\" });\r\n }\r\n }\r\n\r\n private async getFaceCrop(video: HTMLVideoElement, landmarks: NormalizedLandmark[]): Promise<HTMLCanvasElement> {\r\n const ctx = this.offscreenCanvas.getContext(\"2d\")!;\r\n const xs = landmarks.map(l => l.x * video.videoWidth);\r\n const ys = landmarks.map(l => l.y * video.videoHeight);\r\n \r\n const minX = Math.min(...xs);\r\n const maxX = Math.max(...xs);\r\n const minY = Math.min(...ys);\r\n const maxY = Math.max(...ys);\r\n \r\n const width = maxX - minX;\r\n const height = maxY - minY;\r\n const margin = width * 0.3;\r\n\r\n const sourceX = Math.max(0, minX - margin);\r\n const sourceY = Math.max(0, minY - margin);\r\n const sourceW = Math.min(video.videoWidth - sourceX, width + margin * 2);\r\n const sourceH = Math.min(video.videoHeight - sourceY, height + margin * 2);\r\n\r\n try {\r\n // 2. Extract the bitmap (This bypasses many canvas-tainting triggers)\r\n const bitmap = await createImageBitmap(video, sourceX, sourceY, sourceW, sourceH);\r\n \r\n const ctx = this.offscreenCanvas.getContext(\"2d\")!;\r\n ctx.clearRect(0, 0, 224, 224);\r\n \r\n // 3. Draw the clean bitmap to the offscreen canvas\r\n ctx.drawImage(bitmap, 0, 0, 224, 224);\r\n \r\n // 4. Important: close the bitmap to free memory\r\n bitmap.close();\r\n } catch (e) {\r\n console.error(\"[LivenessEngine] Bitmap extraction failed, falling back to direct draw\", e);\r\n // Fallback if createImageBitmap is not supported or fails\r\n const ctx = this.offscreenCanvas.getContext(\"2d\")!;\r\n ctx.drawImage(video, sourceX, sourceY, sourceW, sourceH, 0, 0, 224, 224);\r\n }\r\n\r\n return this.offscreenCanvas;\r\n }\r\n}","import { Injectable, NgZone, OnDestroy } from '@angular/core';\r\nimport { BehaviorSubject, Observable } from 'rxjs';\r\nimport { LivenessEngine, LivenessState, LivenessEngineConfig } from '../core/LivenessEngine';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class LivenessService implements OnDestroy {\r\n private engine!: LivenessEngine;\r\n private stateSubject = new BehaviorSubject<LivenessState | null>(null);\r\n \r\n // Components will subscribe to this\r\n public state$: Observable<LivenessState | null> = this.stateSubject.asObservable();\r\n\r\n constructor(private ngZone: NgZone) {}\r\n\r\n public init(config: LivenessEngineConfig) {\r\n // Run inside runOutsideAngular to prevent 60fps change detection triggers\r\n this.ngZone.runOutsideAngular(() => {\r\n this.engine = new LivenessEngine({\r\n ...config,\r\n onStateChange: (state) => {\r\n // Bring state changes BACK into the zone so the UI updates\r\n this.ngZone.run(() => this.stateSubject.next(state));\r\n }\r\n });\r\n this.engine.loadModels();\r\n });\r\n }\r\n\r\n public attach(video: HTMLVideoElement) {\r\n this.engine?.attachVideo(video);\r\n }\r\n\r\n public start() {\r\n this.engine?.start();\r\n }\r\n\r\n public reset() {\r\n this.engine?.reset();\r\n }\r\n\r\n ngOnDestroy() {\r\n this.engine?.stop();\r\n }\r\n}","import { Component, ElementRef, ViewChild, AfterViewInit, Input, Output, EventEmitter, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';\r\nimport { LivenessService } from './liveness.service';\r\nimport { LivenessSDKResult, Challenge, LivenessState } from '../core/LivenessEngine';\r\nimport { CommonModule } from '@angular/common'\r\n\r\n@Component({\r\n selector: 'LivenessCheck',\r\n standalone: true, // Make it standalone\r\n imports: [CommonModule], // Add CommonModule here to fix NG8002\r\n templateUrl: './liveness.component.html',\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\n\r\nexport class LivenessComponent implements OnInit, AfterViewInit, OnDestroy {\r\n @ViewChild('webcam') webcamRef!: ElementRef<HTMLVideoElement>;\r\n\r\n // --- Logic Configuration ---\r\n @Input() apiUrl!: string;\r\n @Input() duration = 60;\r\n @Input() smileThreshold?: number;\r\n @Input() blinkThreshold?: number;\r\n @Input() minturnHeadThreshold?: number;\r\n @Input() maxturnHeadThreshold?: number;\r\n\r\n // --- Styling Configuration (Class Names) ---\r\n @Input() containerClass = '';\r\n @Input() videoWrapperClass = '';\r\n @Input() videoClass = '';\r\n @Input() timerClass = '';\r\n @Input() stateClass = '';\r\n @Input() challengeTextClass = '';\r\n @Input() buttonClass = '';\r\n @Input() retryButtonClass = '';\r\n @Input() statusOverlayClass = '';\r\n @Input() successMessageClass = '';\r\n @Input() errorMessageClass = '';\r\n @Input() instructionBoxClass = '';\r\n\r\n // --- Content Configuration ---\r\n @Input() successMessage = 'Verification Successful!';\r\n @Input() errorMessage = 'Verification failed. Please try again.';\r\n @Input() retryButtonLabel = 'Try Again';\r\n @Input() startButtonLabel = 'Start Verification';\r\n @Input() challengeMapping: Record<Challenge, string> = {\r\n 'Smile': 'Smile',\r\n 'Blink': 'Blink',\r\n 'Turn_Head': 'Turn Head',\r\n 'Thumbs_Up': 'Thumbs Up' // Default with a space\r\n };\r\n\r\n @Output() onComplete = new EventEmitter<LivenessSDKResult>();\r\n @Output() onError = new EventEmitter<any>();\r\n @Output() onStateChange = new EventEmitter<LivenessState | null>();\r\n\r\n constructor(public liveness: LivenessService) {}\r\n\r\n ngOnInit() {\r\n // Pass the custom thresholds directly to the service\r\n \r\n\r\n this.liveness.state$.subscribe(state => {\r\n // This bridges the Service to the Component's @Output\r\n this.onStateChange.emit(state);\r\n });\r\n\r\n }\r\n\r\n async ngAfterViewInit() {\r\n try {\r\n const stream = await navigator.mediaDevices.getUserMedia({ \r\n video: { width: 640, height: 480, facingMode: 'user' } \r\n });\r\n const video = this.webcamRef.nativeElement;\r\n video.srcObject = stream;\r\n video.onloadedmetadata = () => {\r\n video.play();\r\n\r\n this.liveness.init({\r\n apiUrl: this.apiUrl,\r\n duration: this.duration,\r\n smileThreshold: this.smileThreshold,\r\n blinkThreshold: this.blinkThreshold,\r\n minturnHeadThreshold: this.minturnHeadThreshold,\r\n maxturnHeadThreshold: this.maxturnHeadThreshold,\r\n onComplete: (res) => this.onComplete.emit(res),\r\n onError: (err) => this.onError.emit(err)\r\n });\r\n\r\n this.liveness.attach(video);\r\n };\r\n } catch (e) {\r\n this.onError.emit({ success: false, reason: 'Camera access denied' });\r\n }\r\n }\r\n\r\n ngOnDestroy() {\r\n const stream = this.webcamRef?.nativeElement?.srcObject as MediaStream;\r\n stream?.getTracks().forEach(track => track.stop());\r\n }\r\n}","<div [ngClass]=\"containerClass\">\r\n <div [ngClass]=\"videoWrapperClass\">\r\n <video #webcam \r\n autoplay \r\n playsinline \r\n muted \r\n [ngClass]=\"videoClass\" \r\n style=\"transform: scaleX(-1);\">\r\n </video>\r\n\r\n <ng-container *ngIf=\"(liveness.state$ | async) as state\">\r\n <div [ngClass]=\"statusOverlayClass\">\r\n \r\n <div class=\"instruction-box\">\r\n <h2 class=\"status-text\" [ngClass] = \"stateClass\">{{ state.status | uppercase }}</h2>\r\n \r\n <p *ngIf=\"state.status === 'capturing'\" \r\n [ngClass]=\"challengeTextClass\">\r\n {{ challengeMapping[state.sequence[state.currentStep]] }}\r\n </p>\r\n\r\n <p *ngIf=\"state.status === 'success'\"\r\n [ngClass]=\"successMessageClass\">\r\n {{ successMessage }}\r\n </p>\r\n \r\n <p *ngIf=\"state.status === 'error' || state.status === 'expired'\" \r\n [ngClass]=\"errorMessageClass\">\r\n {{ errorMessage }}\r\n </p>\r\n </div>\r\n\r\n <div *ngIf=\"state.status === 'capturing'\" \r\n [ngClass]=\"timerClass\">\r\n {{ state.timeLeft }}\r\n </div>\r\n\r\n <div class=\"action-area\">\r\n <button *ngIf=\"state.status === 'ready'\" \r\n (click)=\"liveness.start()\"\r\n [ngClass]=\"buttonClass\">\r\n {{ startButtonLabel }}\r\n </button>\r\n \r\n <button *ngIf=\"state.status === 'error' || state.status === 'expired'\" \r\n (click)=\"liveness.reset()\"\r\n [ngClass]=\"retryButtonClass\">\r\n {{ retryButtonLabel }}\r\n </button>\r\n </div>\r\n\r\n </div>\r\n </ng-container>\r\n </div>\r\n</div>","// src/api.ts\r\n\r\nimport { Challenge } from \"./core/LivenessEngine\";\r\n\r\nexport interface LivenessResponse {\r\n is_live: boolean;\r\n reason?: string;\r\n skin_confidence?: number;\r\n [key: string]: any; // allow extra fields if backend returns more\r\n}\r\n\r\n/**\r\n * Sends captured frames to the backend API for liveness verification.\r\n * @param apiUrl - Base URL of the liveness backend\r\n * @param frameBlobs - Array of Blob objects representing captured frames\r\n * @param challenge - The current challenge string\r\n * @returns LivenessResponse from backend\r\n */\r\nexport const verifyLiveness = async (\r\n apiUrl: string,\r\n frameBlobs: Blob[],\r\n challenge: Challenge[]\r\n): Promise<LivenessResponse> => {\r\n const formData = new FormData();\r\n\r\n frameBlobs.forEach((blob, i) => {\r\n formData.append('files', blob, `frame_${i}.jpg`);\r\n });\r\n formData.append('challenge', JSON.stringify(challenge));\r\n\r\n const response = await fetch(`${apiUrl}/v1/verify`, {\r\n method: 'POST',\r\n body: formData,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(\"Network response was not ok\");\r\n }\r\n\r\n const data: LivenessResponse = await response.json();\r\n return data;\r\n};","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.LivenessService"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"richard.fadiora-liveness-detection.mjs","sources":["../../../src/core/LivenessEngine.ts","../../../src/angular/liveness.service.ts","../../../src/angular/liveness.component.ts","../../../src/angular/liveness.component.html","../../../src/api.ts","../../../src/richard.fadiora-liveness-detection.ts"],"sourcesContent":["// src/core/LivenessEngine.ts\r\nimport { FaceLandmarker, HandLandmarker, FilesetResolver, NormalizedLandmark } from \"@mediapipe/tasks-vision\";\r\n\r\nexport type Challenge = \"Smile\" | \"Blink\" | \"Turn_Head\" | \"Thumbs_Up\";\r\n\r\nexport interface ChallengeSnapshot {\r\n challenge: Challenge;\r\n image: string; // Base64 data URL\r\n timestamp: number;\r\n}\r\n\r\nexport interface LivenessSDKResult {\r\n success: boolean;\r\n image?: string;\r\n reason?: string;\r\n skinConfidence?: number;\r\n snapshots?: ChallengeSnapshot[];\r\n}\r\n\r\nexport interface LivenessState {\r\n status: \"loading\" | \"ready\" | \"capturing\" | \"verifying\" | \"success\" | \"error\" | \"expired\";\r\n sequence: Challenge[];\r\n currentStep: number;\r\n timeLeft: number;\r\n isStepTransitioning: boolean;\r\n errorMsg: string;\r\n snapshots: ChallengeSnapshot[];\r\n}\r\n\r\nexport interface LivenessEngineConfig {\r\n apiUrl: string;\r\n duration?: number;\r\n smileThreshold?: number;\r\n blinkThreshold?: number;\r\n minturnHeadThreshold?: number;\r\n maxturnHeadThreshold?: number;\r\n onStateChange?: (state: LivenessState) => void;\r\n onComplete?: (result: LivenessSDKResult) => void;\r\n onError?: (error: LivenessSDKResult) => void;\r\n}\r\n\r\nexport class LivenessEngine {\r\n private config: Required<LivenessEngineConfig>;\r\n private models: { face: FaceLandmarker | null; hand: HandLandmarker | null } = { face: null, hand: null };\r\n private webcam: HTMLVideoElement | null = null;\r\n private state: LivenessState;\r\n \r\n private currentStepRef = 0;\r\n private isStepTransitioningRef = false;\r\n private timerId: ReturnType<typeof setInterval> | null = null;\r\n private requestId: number | null = null;\r\n private heartbeatId: ReturnType<typeof setInterval> | null = null;\r\n\r\n private warningCount = 0;\r\n private readonly MAX_WARNINGS = 3;\r\n private lastWarningMsg = \"\";\r\n private isDetectionPaused = false;\r\n \r\n // --- NEW SECURITY TRACKERS ---\r\n private anchorRatios: number | null = null;\r\n private lastNosePos: { x: number; y: number } | null = null;\r\n private consecutiveMissingFrames = 0;\r\n private readonly MAX_GAP = 15; // ~250ms buffer\r\n private readonly LIVENESS_LOCK_KEY = \"liveness_active_session\";\r\n private stabilityFrames = 0;\r\n private readonly REQUIRED_STABILITY = 10; // Wait for ~10 clear frames before locking\r\n \r\n private offscreenCanvas = document.createElement(\"canvas\");\r\n private CHALLENGE_POOL: Challenge[] = [\"Smile\", \"Blink\", \"Turn_Head\", \"Thumbs_Up\"];\r\n\r\n constructor(config: LivenessEngineConfig) {\r\n this.config = {\r\n apiUrl: config.apiUrl,\r\n duration: config.duration ?? 60,\r\n smileThreshold: config.smileThreshold ?? 0.2,\r\n blinkThreshold: config.blinkThreshold ?? 0.012,\r\n minturnHeadThreshold: config.minturnHeadThreshold ?? 0.15,\r\n maxturnHeadThreshold: config.maxturnHeadThreshold ?? 0.85,\r\n onStateChange: config.onStateChange || (() => {}),\r\n onComplete: config.onComplete || (() => {}),\r\n onError: config.onError || (() => {}),\r\n };\r\n\r\n this.state = {\r\n status: \"loading\",\r\n sequence: [],\r\n currentStep: 0,\r\n timeLeft: this.config.duration,\r\n isStepTransitioning: false,\r\n errorMsg: \"\",\r\n snapshots: [],\r\n };\r\n \r\n this.offscreenCanvas.width = 224;\r\n this.offscreenCanvas.height = 224;\r\n }\r\n\r\n /**\r\n * Phase 1: Load AI Assets (Call this immediately on mount)\r\n */\r\n public async loadModels() {\r\n console.log(\"[LivenessEngine] Loading AI Models...\");\r\n try {\r\n const vision = await FilesetResolver.forVisionTasks(\r\n \"https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.3/wasm\"\r\n );\r\n\r\n this.models.face = await FaceLandmarker.createFromOptions(vision, {\r\n baseOptions: {\r\n modelAssetPath: \"https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task\",\r\n delegate: \"GPU\",\r\n },\r\n outputFaceBlendshapes: true,\r\n runningMode: \"VIDEO\",\r\n });\r\n\r\n this.models.hand = await HandLandmarker.createFromOptions(vision, {\r\n baseOptions: {\r\n modelAssetPath: \"https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task\",\r\n delegate: \"GPU\",\r\n },\r\n runningMode: \"VIDEO\",\r\n numHands: 1,\r\n });\r\n\r\n this.generateSequence();\r\n // Stay in 'loading' or move to a 'ready_to_mount' status if you prefer\r\n // For now, we move to ready to signal the UI can show the camera\r\n this.updateState({ status: \"ready\" });\r\n console.log(\"[LivenessEngine] Models Loaded.\");\r\n } catch (err) {\r\n console.error(\"[LivenessEngine] Init Error:\", err);\r\n this.updateState({ status: \"error\", errorMsg: \"Failed to load security assets.\" });\r\n }\r\n }\r\n\r\n /**\r\n * Phase 2: Attach Video (Call this once the Webcam is in the DOM)\r\n */\r\n public attachVideo = (video: HTMLVideoElement) => {\r\n video.setAttribute('crossorigin', 'anonymous');\r\n this.webcam = video;\r\n console.log(\"[LivenessEngine] Video stream attached.\");\r\n };\r\n\r\n // --- NEW SECURITY METHODS ---\r\n private verifyIdentity(landmarks: NormalizedLandmark[]): boolean {\r\n const eyeDist = Math.sqrt(\r\n Math.pow(landmarks[33].x - landmarks[263].x, 2) + \r\n Math.pow(landmarks[33].y - landmarks[263].y, 2)\r\n );\r\n const noseToMouth = Math.abs(landmarks[1].y - landmarks[13].y);\r\n const currentRatio = eyeDist / (noseToMouth || 1);\r\n\r\n if (this.anchorRatios === null) {\r\n this.anchorRatios = currentRatio;\r\n return true;\r\n }\r\n\r\n const diff = Math.abs(this.anchorRatios - currentRatio) / this.anchorRatios;\r\n return diff < 0.70; // 70% tolerance for head tilt\r\n }\r\n\r\n private checkMovement(landmarks: NormalizedLandmark[]): boolean {\r\n const nose = { x: landmarks[1].x, y: landmarks[1].y };\r\n if (this.lastNosePos) {\r\n const dist = Math.sqrt(\r\n Math.pow(nose.x - this.lastNosePos.x, 2) + \r\n Math.pow(nose.y - this.lastNosePos.y, 2)\r\n );\r\n if (dist > 0.5) return false; // Sudden teleportation\r\n }\r\n this.lastNosePos = nose;\r\n return true;\r\n }\r\n\r\n private handleViolation(reason: string) {\r\n this.warningCount++;\r\n\r\n if (this.warningCount >= this.MAX_WARNINGS) {\r\n this.failInstantly(reason);\r\n } else {\r\n this.isDetectionPaused = true; // Set BEFORE cancelling\r\n if (this.requestId) {\r\n cancelAnimationFrame(this.requestId);\r\n this.requestId = null;\r\n }\r\n this.updateState({ errorMsg: `${reason} (Warning ${this.warningCount}/${this.MAX_WARNINGS})` });\r\n \r\n setTimeout(() => {\r\n if (this.state.status !== \"capturing\") return\r\n this.isDetectionPaused = false;\r\n this.updateState({ errorMsg: \"\" });\r\n this.detectLoop();\r\n }, 2000); // Give user 2 seconds to adjust\r\n }\r\n}\r\n\r\n private failInstantly(reason: string) {\r\n this.stop();\r\n this.updateState({ status: \"error\", errorMsg: reason, isStepTransitioning: false });\r\n this.config.onError({ success: false, reason });\r\n }\r\n\r\n public start = () => {\r\n // Multi-tab Prevention\r\n const active = localStorage.getItem(this.LIVENESS_LOCK_KEY);\r\n if (active && Date.now() - parseInt(active) < 5000) {\r\n this.failInstantly(\"Another session is active.\");\r\n return;\r\n }\r\n\r\n this.heartbeatId = setInterval(() => {\r\n localStorage.setItem(this.LIVENESS_LOCK_KEY, Date.now().toString());\r\n }, 1000);\r\n\r\n if (this.state.status !== \"ready\" || !this.webcam) {\r\n console.warn(\"[LivenessEngine] Engine not ready or video missing.\");\r\n return;\r\n }\r\n\r\n console.log(\"[LivenessEngine] Session Starting...\");\r\n this.state.status = \"capturing\"; // Sync internal status immediately\r\n this.updateState({ status: \"capturing\" });\r\n this.startTimer();\r\n this.detectLoop();\r\n };\r\n\r\n public stop = () => {\r\n if (this.timerId) clearInterval(this.timerId);\r\n if (this.heartbeatId) clearInterval(this.heartbeatId);\r\n if (this.requestId) cancelAnimationFrame(this.requestId);\r\n localStorage.removeItem(this.LIVENESS_LOCK_KEY);\r\n\r\n this.timerId = null;\r\n this.heartbeatId = null;\r\n this.requestId = null;\r\n };\r\n\r\n public reset = () => {\r\n this.stop();\r\n this.currentStepRef = 0;\r\n this.isStepTransitioningRef = false;\r\n this.anchorRatios = null;\r\n this.lastNosePos = null;\r\n this.consecutiveMissingFrames = 0;\r\n this.stabilityFrames = 0;\r\n this.warningCount = 0; \r\n this.isDetectionPaused = false;\r\n this.generateSequence();\r\n this.updateState({\r\n status: \"ready\",\r\n currentStep: 0,\r\n timeLeft: this.config.duration,\r\n isStepTransitioning: false,\r\n errorMsg: \"\",\r\n snapshots: [],\r\n });\r\n};\r\n\r\n private updateState(newState: Partial<LivenessState>) {\r\n this.state = { ...this.state, ...newState };\r\n this.config.onStateChange(this.state);\r\n }\r\n\r\n private generateSequence(): Challenge[] {\r\n const seq = [...this.CHALLENGE_POOL].sort(() => 0.5 - Math.random()).slice(0, 3);\r\n this.updateState({ sequence: seq });\r\n return seq;\r\n }\r\n\r\n private startTimer() {\r\n if (this.timerId) clearInterval(this.timerId);\r\n this.timerId = setInterval(() => {\r\n if (this.state.timeLeft > 0) {\r\n this.updateState({ timeLeft: this.state.timeLeft - 1 });\r\n } else {\r\n this.stop();\r\n this.updateState({ status: \"expired\" });\r\n }\r\n }, 1000);\r\n }\r\n\r\n private detectLoop = () => {\r\n if (this.state.status !== \"capturing\" || !this.webcam || !this.models.face || this.isDetectionPaused) return;\r\n\r\n const now = performance.now();\r\n try {\r\n const faceRes = this.models.face.detectForVideo(this.webcam, now);\r\n \r\n // --- NEW SECURITY CHECKS ---\r\n // 1. Multi-Face Security\r\n if (faceRes.faceLandmarks && faceRes.faceLandmarks.length > 1) {\r\n console.warn(\"[LivenessEngine] Security Alert: Multiple faces detected!\");\r\n this.handleViolation(\"Multiple faces detected. Please ensure only one person is in frame.\");\r\n return; // CRITICAL: Stop execution here\r\n }\r\n \r\n const landmarks = faceRes.faceLandmarks?.[0];\r\n\r\n // 2. Continuity & Identity Security\r\n if (!landmarks) {\r\n this.consecutiveMissingFrames++;\r\n if (this.consecutiveMissingFrames > this.MAX_GAP) {\r\n return this.handleViolation(\"Face lost. Session reset.\");\r\n }\r\n } else {\r\n this.consecutiveMissingFrames = 0;\r\n\r\n if (this.anchorRatios === null) {\r\n this.stabilityFrames++;\r\n if (this.stabilityFrames >= this.REQUIRED_STABILITY) {\r\n this.verifyIdentity(landmarks); // This sets the anchor for the first time\r\n }\r\n } else {\r\n // Only perform the security check AFTER the anchor is established\r\n if (!this.verifyIdentity(landmarks) || !this.checkMovement(landmarks)) {\r\n this.handleViolation(\"Security violation: Identity mismatch.\");\r\n return;\r\n }\r\n }\r\n\r\n if (this.state.errorMsg) this.updateState({ errorMsg: \"\" });\r\n\r\n // 3. Challenge Logic\r\n const currentChallenge = this.state.sequence[this.currentStepRef];\r\n const handRes = this.models.hand?.detectForVideo(this.webcam, now);\r\n\r\n if (this.checkAction(faceRes, handRes, currentChallenge)) {\r\n this.handleStepSuccess(landmarks); // Pass landmarks to capture\r\n return; \r\n }\r\n }\r\n\r\n this.requestId = requestAnimationFrame(this.detectLoop);\r\n\r\n } catch (err) {\r\n console.error(\"[LivenessEngine] Loop detection error:\", err);\r\n this.requestId = requestAnimationFrame(this.detectLoop);\r\n }\r\n\r\n };\r\n\r\n private async handleStepSuccess(landmarks: NormalizedLandmark[]) {\r\n if (this.isStepTransitioningRef) return;\r\n \r\n this.isStepTransitioningRef = true;\r\n\r\n // Capture Snapshot\r\n const canvas = await this.getFaceCrop(this.webcam!, landmarks);\r\n const snapshot: ChallengeSnapshot = {\r\n challenge: this.state.sequence[this.currentStepRef],\r\n image: canvas.toDataURL(\"image/jpeg\", 0.7),\r\n timestamp: Date.now()\r\n };\r\n\r\n const updatedSnapshots = [...this.state.snapshots, snapshot];\r\n\r\n this.updateState({ isStepTransitioning: true, snapshots: updatedSnapshots });\r\n\r\n setTimeout(() => {\r\n // Check if engine was stopped during the timeout\r\n if (this.state.status !== \"capturing\") return;\r\n\r\n if (this.currentStepRef < this.state.sequence.length - 1) {\r\n this.currentStepRef++;\r\n this.isStepTransitioningRef = false;\r\n this.updateState({\r\n currentStep: this.currentStepRef,\r\n isStepTransitioning: false,\r\n snapshots: updatedSnapshots,\r\n });\r\n this.requestId = requestAnimationFrame(this.detectLoop);\r\n } else {\r\n this.updateState({ snapshots: updatedSnapshots });\r\n this.sendFinalProof();\r\n }\r\n }, 1500);\r\n }\r\n\r\n private checkAction(faceRes: any, handRes: any, challenge: Challenge): boolean {\r\n if (this.isStepTransitioningRef) return false;\r\n\r\n if (challenge === \"Thumbs_Up\" && handRes?.landmarks?.length > 0) {\r\n const l = handRes.landmarks[0];\r\n return l[4].y < l[2].y && [8, 12, 16, 20].every(i => l[i].y > l[i - 2].y);\r\n }\r\n\r\n if (faceRes?.faceLandmarks?.length > 0) {\r\n const lms: NormalizedLandmark[] = faceRes.faceLandmarks[0];\r\n switch (challenge) {\r\n case \"Smile\":\r\n return (lms[291].x - lms[61].x) > this.config.smileThreshold;\r\n case \"Blink\":\r\n const leftEye = Math.abs(lms[159].y - lms[145].y);\r\n const rightEye = Math.abs(lms[386].y - lms[374].y);\r\n return ((leftEye + rightEye) / 2) < this.config.blinkThreshold;\r\n case \"Turn_Head\":\r\n const yaw = (lms[1].x - lms[33].x) / (lms[263].x - lms[33].x);\r\n return yaw < this.config.minturnHeadThreshold || yaw > this.config.maxturnHeadThreshold;\r\n default: return false;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n private async sendFinalProof() {\r\n this.stop();\r\n this.updateState({ status: \"verifying\" });\r\n\r\n try {\r\n const blobs: Blob[] = [];\r\n let finalBase64 = \"\";\r\n\r\n for (let i = 0; i < 5; i++) {\r\n if (!this.webcam || !this.models.face) break;\r\n const faceRes = this.models.face?.detectForVideo(this.webcam, performance.now());\r\n if (faceRes?.faceLandmarks?.[0]) {\r\n const canvas = await this.getFaceCrop(this.webcam, faceRes.faceLandmarks[0]);\r\n const blob = await new Promise<Blob | null>(res => canvas.toBlob(res, \"image/jpeg\", 0.9));\r\n if (blob) blobs.push(blob);\r\n if (i === 4) finalBase64 = canvas.toDataURL(\"image/jpeg\");\r\n }\r\n await new Promise(r => setTimeout(r, 100));\r\n }\r\n\r\n const { verifyLiveness } = await import(\"../api\");\r\n const result = await verifyLiveness(this.config.apiUrl, blobs, this.state.sequence);\r\n\r\n if (result.is_live) {\r\n this.updateState({ status: \"success\" });\r\n this.config.onComplete({ success: true, image: finalBase64, skinConfidence: result.skin_confidence });\r\n } else {\r\n const reason = result.reason || \"Liveness check failed\";\r\n this.updateState({ status: \"error\", errorMsg: reason });\r\n this.config.onError({ success: false, reason });\r\n }\r\n } catch (err) {\r\n this.updateState({ status: \"error\", errorMsg: \"Verification failed.\" });\r\n this.config.onError({ success: false, reason: \"Network error\" });\r\n }\r\n }\r\n\r\n private async getFaceCrop(video: HTMLVideoElement, landmarks: NormalizedLandmark[]): Promise<HTMLCanvasElement> {\r\n \r\n const xs = landmarks.map(l => l.x * video.videoWidth);\r\n const ys = landmarks.map(l => l.y * video.videoHeight);\r\n \r\n const minX = Math.min(...xs);\r\n const maxX = Math.max(...xs);\r\n const minY = Math.min(...ys);\r\n const maxY = Math.max(...ys);\r\n \r\n const width = maxX - minX;\r\n const height = maxY - minY;\r\n const margin = width * 0.3;\r\n\r\n const sourceX = Math.max(0, minX - margin);\r\n const sourceY = Math.max(0, minY - margin);\r\n const sourceW = Math.min(video.videoWidth - sourceX, width + margin * 2);\r\n const sourceH = Math.min(video.videoHeight - sourceY, height + margin * 2);\r\n\r\n const ctx = this.offscreenCanvas.getContext(\"2d\")!;\r\n\r\n try {\r\n // 2. Extract the bitmap (This bypasses many canvas-tainting triggers)\r\n const bitmap = await createImageBitmap(video, sourceX, sourceY, sourceW, sourceH);\r\n \r\n ctx.clearRect(0, 0, 224, 224);\r\n \r\n // 3. Draw the clean bitmap to the offscreen canvas\r\n ctx.drawImage(bitmap, 0, 0, 224, 224);\r\n \r\n // 4. Important: close the bitmap to free memory\r\n bitmap.close();\r\n } catch (e) {\r\n console.error(\"[LivenessEngine] Bitmap extraction failed, falling back to direct draw\", e);\r\n // Fallback if createImageBitmap is not supported or fails\r\n const ctx = this.offscreenCanvas.getContext(\"2d\")!;\r\n ctx.drawImage(video, sourceX, sourceY, sourceW, sourceH, 0, 0, 224, 224);\r\n }\r\n\r\n return this.offscreenCanvas;\r\n }\r\n}","import { Injectable, NgZone, OnDestroy } from '@angular/core';\r\nimport { BehaviorSubject, Observable } from 'rxjs';\r\nimport { LivenessEngine, LivenessState, LivenessEngineConfig } from '../core/LivenessEngine';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class LivenessService implements OnDestroy {\r\n private engine!: LivenessEngine;\r\n private stateSubject = new BehaviorSubject<LivenessState | null>(null);\r\n \r\n // Components will subscribe to this\r\n public state$: Observable<LivenessState | null> = this.stateSubject.asObservable();\r\n\r\n constructor(private ngZone: NgZone) {}\r\n\r\n public init(config: LivenessEngineConfig) {\r\n // Run inside runOutsideAngular to prevent 60fps change detection triggers\r\n this.ngZone.runOutsideAngular(() => {\r\n this.engine = new LivenessEngine({\r\n ...config,\r\n onStateChange: (state) => {\r\n // Bring state changes BACK into the zone so the UI updates\r\n this.ngZone.run(() => this.stateSubject.next(state));\r\n }\r\n });\r\n this.engine.loadModels();\r\n });\r\n }\r\n\r\n public attach(video: HTMLVideoElement) {\r\n this.engine?.attachVideo(video);\r\n }\r\n\r\n public start() {\r\n this.engine?.start();\r\n }\r\n\r\n public reset() {\r\n this.engine?.reset();\r\n }\r\n\r\n ngOnDestroy() {\r\n this.engine?.stop();\r\n }\r\n}","import { Component, ElementRef, ViewChild, AfterViewInit, Input, Output, EventEmitter, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';\r\nimport { LivenessService } from './liveness.service';\r\nimport { LivenessSDKResult, Challenge, LivenessState } from '../core/LivenessEngine';\r\nimport { CommonModule } from '@angular/common'\r\n\r\n@Component({\r\n selector: 'LivenessCheck',\r\n standalone: true, // Make it standalone\r\n imports: [CommonModule], // Add CommonModule here to fix NG8002\r\n templateUrl: './liveness.component.html',\r\n encapsulation: ViewEncapsulation.None,\r\n})\r\n\r\nexport class LivenessComponent implements OnInit, AfterViewInit, OnDestroy {\r\n @ViewChild('webcam') webcamRef!: ElementRef<HTMLVideoElement>;\r\n\r\n // --- Logic Configuration ---\r\n @Input() apiUrl!: string;\r\n @Input() duration = 60;\r\n @Input() smileThreshold?: number;\r\n @Input() blinkThreshold?: number;\r\n @Input() minturnHeadThreshold?: number;\r\n @Input() maxturnHeadThreshold?: number;\r\n\r\n // --- Styling Configuration (Class Names) ---\r\n @Input() containerClass = '';\r\n @Input() videoWrapperClass = '';\r\n @Input() videoClass = '';\r\n @Input() timerClass = '';\r\n @Input() stateClass = '';\r\n @Input() challengeTextClass = '';\r\n @Input() buttonClass = '';\r\n @Input() retryButtonClass = '';\r\n @Input() statusOverlayClass = '';\r\n @Input() successMessageClass = '';\r\n @Input() errorMessageClass = '';\r\n @Input() instructionBoxClass = '';\r\n\r\n // --- Content Configuration ---\r\n @Input() successMessage = 'Verification Successful!';\r\n @Input() errorMessage = 'Verification failed. Please try again.';\r\n @Input() retryButtonLabel = 'Try Again';\r\n @Input() startButtonLabel = 'Start Verification';\r\n @Input() challengeMapping: Record<Challenge, string> = {\r\n 'Smile': 'Smile',\r\n 'Blink': 'Blink',\r\n 'Turn_Head': 'Turn Head',\r\n 'Thumbs_Up': 'Thumbs Up' // Default with a space\r\n };\r\n\r\n @Output() onComplete = new EventEmitter<LivenessSDKResult>();\r\n @Output() onError = new EventEmitter<any>();\r\n @Output() onStateChange = new EventEmitter<LivenessState | null>();\r\n\r\n constructor(public liveness: LivenessService) {}\r\n\r\n ngOnInit() {\r\n // Pass the custom thresholds directly to the service\r\n \r\n\r\n this.liveness.state$.subscribe(state => {\r\n // This bridges the Service to the Component's @Output\r\n this.onStateChange.emit(state);\r\n });\r\n\r\n }\r\n\r\n async ngAfterViewInit() {\r\n try {\r\n const stream = await navigator.mediaDevices.getUserMedia({ \r\n video: { width: 640, height: 480, facingMode: 'user' } \r\n });\r\n const video = this.webcamRef.nativeElement;\r\n video.srcObject = stream;\r\n video.onloadedmetadata = () => {\r\n video.play();\r\n\r\n this.liveness.init({\r\n apiUrl: this.apiUrl,\r\n duration: this.duration,\r\n smileThreshold: this.smileThreshold,\r\n blinkThreshold: this.blinkThreshold,\r\n minturnHeadThreshold: this.minturnHeadThreshold,\r\n maxturnHeadThreshold: this.maxturnHeadThreshold,\r\n onComplete: (res) => this.onComplete.emit(res),\r\n onError: (err) => this.onError.emit(err)\r\n });\r\n\r\n this.liveness.attach(video);\r\n };\r\n } catch (e) {\r\n this.onError.emit({ success: false, reason: 'Camera access denied' });\r\n }\r\n }\r\n\r\n ngOnDestroy() {\r\n const stream = this.webcamRef?.nativeElement?.srcObject as MediaStream;\r\n stream?.getTracks().forEach(track => track.stop());\r\n }\r\n}","<div [ngClass]=\"containerClass\">\r\n <div [ngClass]=\"videoWrapperClass\">\r\n <video #webcam \r\n autoplay \r\n playsinline \r\n muted \r\n [ngClass]=\"videoClass\" \r\n style=\"transform: scaleX(-1);\">\r\n </video>\r\n\r\n <ng-container *ngIf=\"(liveness.state$ | async) as state\">\r\n <div [ngClass]=\"statusOverlayClass\">\r\n \r\n <div class=\"instruction-box\">\r\n <h2 class=\"status-text\" [ngClass] = \"stateClass\">{{ state.status | uppercase }}</h2>\r\n \r\n <p *ngIf=\"state.status === 'capturing'\" \r\n [ngClass]=\"challengeTextClass\">\r\n {{ challengeMapping[state.sequence[state.currentStep]] }}\r\n </p>\r\n\r\n <p *ngIf=\"state.status === 'success'\"\r\n [ngClass]=\"successMessageClass\">\r\n {{ successMessage }}\r\n </p>\r\n \r\n <p *ngIf=\"state.status === 'error' || state.status === 'expired'\" \r\n [ngClass]=\"errorMessageClass\">\r\n {{ errorMessage }}\r\n </p>\r\n </div>\r\n\r\n <div *ngIf=\"state.status === 'capturing'\" \r\n [ngClass]=\"timerClass\">\r\n {{ state.timeLeft }}\r\n </div>\r\n\r\n <div class=\"action-area\">\r\n <button *ngIf=\"state.status === 'ready'\" \r\n (click)=\"liveness.start()\"\r\n [ngClass]=\"buttonClass\">\r\n {{ startButtonLabel }}\r\n </button>\r\n \r\n <button *ngIf=\"state.status === 'error' || state.status === 'expired'\" \r\n (click)=\"liveness.reset()\"\r\n [ngClass]=\"retryButtonClass\">\r\n {{ retryButtonLabel }}\r\n </button>\r\n </div>\r\n\r\n </div>\r\n </ng-container>\r\n </div>\r\n</div>","// src/api.ts\r\n\r\nimport { Challenge } from \"./core/LivenessEngine\";\r\n\r\nexport interface LivenessResponse {\r\n is_live: boolean;\r\n reason?: string;\r\n skin_confidence?: number;\r\n [key: string]: any; // allow extra fields if backend returns more\r\n}\r\n\r\n/**\r\n * Sends captured frames to the backend API for liveness verification.\r\n * @param apiUrl - Base URL of the liveness backend\r\n * @param frameBlobs - Array of Blob objects representing captured frames\r\n * @param challenge - The current challenge string\r\n * @returns LivenessResponse from backend\r\n */\r\nexport const verifyLiveness = async (\r\n apiUrl: string,\r\n frameBlobs: Blob[],\r\n challenge: Challenge[]\r\n): Promise<LivenessResponse> => {\r\n const formData = new FormData();\r\n\r\n frameBlobs.forEach((blob, i) => {\r\n formData.append('files', blob, `frame_${i}.jpg`);\r\n });\r\n formData.append('challenge', JSON.stringify(challenge));\r\n\r\n const response = await fetch(`${apiUrl}/v1/verify`, {\r\n method: 'POST',\r\n body: formData,\r\n });\r\n\r\n if (!response.ok) {\r\n throw new Error(\"Network response was not ok\");\r\n }\r\n\r\n const data: LivenessResponse = await response.json();\r\n return data;\r\n};","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.LivenessService"],"mappings":"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"}
|
|
@@ -45,6 +45,10 @@ declare class LivenessEngine {
|
|
|
45
45
|
private timerId;
|
|
46
46
|
private requestId;
|
|
47
47
|
private heartbeatId;
|
|
48
|
+
private warningCount;
|
|
49
|
+
private readonly MAX_WARNINGS;
|
|
50
|
+
private lastWarningMsg;
|
|
51
|
+
private isDetectionPaused;
|
|
48
52
|
private anchorRatios;
|
|
49
53
|
private lastNosePos;
|
|
50
54
|
private consecutiveMissingFrames;
|
|
@@ -65,6 +69,7 @@ declare class LivenessEngine {
|
|
|
65
69
|
attachVideo: (video: HTMLVideoElement) => void;
|
|
66
70
|
private verifyIdentity;
|
|
67
71
|
private checkMovement;
|
|
72
|
+
private handleViolation;
|
|
68
73
|
private failInstantly;
|
|
69
74
|
start: () => void;
|
|
70
75
|
stop: () => void;
|
|
@@ -41,6 +41,10 @@ export declare class LivenessEngine {
|
|
|
41
41
|
private timerId;
|
|
42
42
|
private requestId;
|
|
43
43
|
private heartbeatId;
|
|
44
|
+
private warningCount;
|
|
45
|
+
private readonly MAX_WARNINGS;
|
|
46
|
+
private lastWarningMsg;
|
|
47
|
+
private isDetectionPaused;
|
|
44
48
|
private anchorRatios;
|
|
45
49
|
private lastNosePos;
|
|
46
50
|
private consecutiveMissingFrames;
|
|
@@ -61,6 +65,7 @@ export declare class LivenessEngine {
|
|
|
61
65
|
attachVideo: (video: HTMLVideoElement) => void;
|
|
62
66
|
private verifyIdentity;
|
|
63
67
|
private checkMovement;
|
|
68
|
+
private handleViolation;
|
|
64
69
|
private failInstantly;
|
|
65
70
|
start: () => void;
|
|
66
71
|
stop: () => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LivenessEngine.d.ts","sourceRoot":"","sources":["../../src/core/LivenessEngine.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,WAAW,GAAG,WAAW,CAAC;AAEtE,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,iBAAiB,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,WAAW,GAAG,WAAW,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IAC1F,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,iBAAiB,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC/C,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACjD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC9C;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,MAAM,CAA4F;IAC1G,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,KAAK,CAAgB;IAE7B,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,sBAAsB,CAAS;IACvC,OAAO,CAAC,OAAO,CAA+C;IAC9D,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,WAAW,CAA+C;
|
|
1
|
+
{"version":3,"file":"LivenessEngine.d.ts","sourceRoot":"","sources":["../../src/core/LivenessEngine.ts"],"names":[],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const k=require("./api-CWu5ff9j.cjs"),m=require("./LivenessCheck-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const k=require("./api-CWu5ff9j.cjs"),m=require("./LivenessCheck-6oh9vnb0.cjs"),u=require("@angular/core"),q=require("@angular/common");var _=function(r,t){return _=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,n){e.__proto__=n}||function(e,n){for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(e[o]=n[o])},_(r,t)};function v(r,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");_(r,t);function e(){this.constructor=r}r.prototype=t===null?Object.create(t):(e.prototype=t.prototype,new e)}function w(r){var t=typeof Symbol=="function"&&Symbol.iterator,e=t&&r[t],n=0;if(e)return e.call(r);if(r&&typeof r.length=="number")return{next:function(){return r&&n>=r.length&&(r=void 0),{value:r&&r[n++],done:!r}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function E(r,t){var e=typeof Symbol=="function"&&r[Symbol.iterator];if(!e)return r;var n=e.call(r),o,s=[],i;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)s.push(o.value)}catch(c){i={error:c}}finally{try{o&&!o.done&&(e=n.return)&&e.call(n)}finally{if(i)throw i.error}}return s}function L(r,t,e){if(e||arguments.length===2)for(var n=0,o=t.length,s;n<o;n++)(s||!(n in t))&&(s||(s=Array.prototype.slice.call(t,0,n)),s[n]=t[n]);return r.concat(s||Array.prototype.slice.call(t))}function h(r){return typeof r=="function"}function B(r){var t=function(n){Error.call(n),n.stack=new Error().stack},e=r(t);return e.prototype=Object.create(Error.prototype),e.prototype.constructor=e,e}var S=B(function(r){return function(e){r(this),this.message=e?e.length+` errors occurred during unsubscription:
|
|
2
2
|
`+e.map(function(n,o){return o+1+") "+n.toString()}).join(`
|
|
3
3
|
`):"",this.name="UnsubscriptionError",this.errors=e}});function O(r,t){if(r){var e=r.indexOf(t);0<=e&&r.splice(e,1)}}var g=function(){function r(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return r.prototype.unsubscribe=function(){var t,e,n,o,s;if(!this.closed){this.closed=!0;var i=this._parentage;if(i)if(this._parentage=null,Array.isArray(i))try{for(var c=w(i),p=c.next();!p.done;p=c.next()){var C=p.value;C.remove(this)}}catch(l){t={error:l}}finally{try{p&&!p.done&&(e=c.return)&&e.call(c)}finally{if(t)throw t.error}}else i.remove(this);var T=this.initialTeardown;if(h(T))try{T()}catch(l){s=l instanceof S?l.errors:[l]}var x=this._finalizers;if(x){this._finalizers=null;try{for(var d=w(x),f=d.next();!f.done;f=d.next()){var F=f.value;try{P(F)}catch(l){s=s??[],l instanceof S?s=L(L([],E(s)),E(l.errors)):s.push(l)}}}catch(l){n={error:l}}finally{try{f&&!f.done&&(o=d.return)&&o.call(d)}finally{if(n)throw n.error}}}if(s)throw new S(s)}},r.prototype.add=function(t){var e;if(t&&t!==this)if(this.closed)P(t);else{if(t instanceof r){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(e=this._finalizers)!==null&&e!==void 0?e:[]).push(t)}},r.prototype._hasParent=function(t){var e=this._parentage;return e===t||Array.isArray(e)&&e.includes(t)},r.prototype._addParent=function(t){var e=this._parentage;this._parentage=Array.isArray(e)?(e.push(t),e):e?[e,t]:t},r.prototype._removeParent=function(t){var e=this._parentage;e===t?this._parentage=null:Array.isArray(e)&&O(e,t)},r.prototype.remove=function(t){var e=this._finalizers;e&&O(e,t),t instanceof r&&t._removeParent(this)},r.EMPTY=function(){var t=new r;return t.closed=!0,t}(),r}(),V=g.EMPTY;function D(r){return r instanceof g||r&&"closed"in r&&h(r.remove)&&h(r.add)&&h(r.unsubscribe)}function P(r){h(r)?r():r.unsubscribe()}var Y={Promise:void 0},$={setTimeout:function(r,t){for(var e=[],n=2;n<arguments.length;n++)e[n-2]=arguments[n];return setTimeout.apply(void 0,L([r,t],E(e)))},clearTimeout:function(r){return clearTimeout(r)},delegate:void 0};function Z(r){$.setTimeout(function(){throw r})}function j(){}function b(r){r()}var H=function(r){v(t,r);function t(e){var n=r.call(this)||this;return n.isStopped=!1,e?(n.destination=e,D(e)&&e.add(n)):n.destination=G,n}return t.create=function(e,n,o){return new I(e,n,o)},t.prototype.next=function(e){this.isStopped||this._next(e)},t.prototype.error=function(e){this.isStopped||(this.isStopped=!0,this._error(e))},t.prototype.complete=function(){this.isStopped||(this.isStopped=!0,this._complete())},t.prototype.unsubscribe=function(){this.closed||(this.isStopped=!0,r.prototype.unsubscribe.call(this),this.destination=null)},t.prototype._next=function(e){this.destination.next(e)},t.prototype._error=function(e){try{this.destination.error(e)}finally{this.unsubscribe()}},t.prototype._complete=function(){try{this.destination.complete()}finally{this.unsubscribe()}},t}(g),K=function(){function r(t){this.partialObserver=t}return r.prototype.next=function(t){var e=this.partialObserver;if(e.next)try{e.next(t)}catch(n){y(n)}},r.prototype.error=function(t){var e=this.partialObserver;if(e.error)try{e.error(t)}catch(n){y(n)}else y(t)},r.prototype.complete=function(){var t=this.partialObserver;if(t.complete)try{t.complete()}catch(e){y(e)}},r}(),I=function(r){v(t,r);function t(e,n,o){var s=r.call(this)||this,i;return h(e)||!e?i={next:e??void 0,error:n??void 0,complete:o??void 0}:i=e,s.destination=new K(i),s}return t}(H);function y(r){Z(r)}function W(r){throw r}var G={closed:!0,next:j,error:W,complete:j},J=function(){return typeof Symbol=="function"&&Symbol.observable||"@@observable"}();function Q(r){return r}function X(r){return r.length===0?Q:r.length===1?r[0]:function(e){return r.reduce(function(n,o){return o(n)},e)}}var A=function(){function r(t){t&&(this._subscribe=t)}return r.prototype.lift=function(t){var e=new r;return e.source=this,e.operator=t,e},r.prototype.subscribe=function(t,e,n){var o=this,s=N(t)?t:new I(t,e,n);return b(function(){var i=o,c=i.operator,p=i.source;s.add(c?c.call(s,p):p?o._subscribe(s):o._trySubscribe(s))}),s},r.prototype._trySubscribe=function(t){try{return this._subscribe(t)}catch(e){t.error(e)}},r.prototype.forEach=function(t,e){var n=this;return e=M(e),new e(function(o,s){var i=new I({next:function(c){try{t(c)}catch(p){s(p),i.unsubscribe()}},error:s,complete:o});n.subscribe(i)})},r.prototype._subscribe=function(t){var e;return(e=this.source)===null||e===void 0?void 0:e.subscribe(t)},r.prototype[J]=function(){return this},r.prototype.pipe=function(){for(var t=[],e=0;e<arguments.length;e++)t[e]=arguments[e];return X(t)(this)},r.prototype.toPromise=function(t){var e=this;return t=M(t),new t(function(n,o){var s;e.subscribe(function(i){return s=i},function(i){return o(i)},function(){return n(s)})})},r.create=function(t){return new r(t)},r}();function M(r){var t;return(t=r??Y.Promise)!==null&&t!==void 0?t:Promise}function z(r){return r&&h(r.next)&&h(r.error)&&h(r.complete)}function N(r){return r&&r instanceof H||z(r)&&D(r)}var ee=B(function(r){return function(){r(this),this.name="ObjectUnsubscribedError",this.message="object unsubscribed"}}),R=function(r){v(t,r);function t(){var e=r.call(this)||this;return e.closed=!1,e.currentObservers=null,e.observers=[],e.isStopped=!1,e.hasError=!1,e.thrownError=null,e}return t.prototype.lift=function(e){var n=new U(this,this);return n.operator=e,n},t.prototype._throwIfClosed=function(){if(this.closed)throw new ee},t.prototype.next=function(e){var n=this;b(function(){var o,s;if(n._throwIfClosed(),!n.isStopped){n.currentObservers||(n.currentObservers=Array.from(n.observers));try{for(var i=w(n.currentObservers),c=i.next();!c.done;c=i.next()){var p=c.value;p.next(e)}}catch(C){o={error:C}}finally{try{c&&!c.done&&(s=i.return)&&s.call(i)}finally{if(o)throw o.error}}}})},t.prototype.error=function(e){var n=this;b(function(){if(n._throwIfClosed(),!n.isStopped){n.hasError=n.isStopped=!0,n.thrownError=e;for(var o=n.observers;o.length;)o.shift().error(e)}})},t.prototype.complete=function(){var e=this;b(function(){if(e._throwIfClosed(),!e.isStopped){e.isStopped=!0;for(var n=e.observers;n.length;)n.shift().complete()}})},t.prototype.unsubscribe=function(){this.isStopped=this.closed=!0,this.observers=this.currentObservers=null},Object.defineProperty(t.prototype,"observed",{get:function(){var e;return((e=this.observers)===null||e===void 0?void 0:e.length)>0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(e){return this._throwIfClosed(),r.prototype._trySubscribe.call(this,e)},t.prototype._subscribe=function(e){return this._throwIfClosed(),this._checkFinalizedStatuses(e),this._innerSubscribe(e)},t.prototype._innerSubscribe=function(e){var n=this,o=this,s=o.hasError,i=o.isStopped,c=o.observers;return s||i?V:(this.currentObservers=null,c.push(e),new g(function(){n.currentObservers=null,O(c,e)}))},t.prototype._checkFinalizedStatuses=function(e){var n=this,o=n.hasError,s=n.thrownError,i=n.isStopped;o?e.error(s):i&&e.complete()},t.prototype.asObservable=function(){var e=new A;return e.source=this,e},t.create=function(e,n){return new U(e,n)},t}(A),U=function(r){v(t,r);function t(e,n){var o=r.call(this)||this;return o.destination=e,o.source=n,o}return t.prototype.next=function(e){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,e)},t.prototype.error=function(e){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,e)},t.prototype.complete=function(){var e,n;(n=(e=this.destination)===null||e===void 0?void 0:e.complete)===null||n===void 0||n.call(e)},t.prototype._subscribe=function(e){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(e))!==null&&o!==void 0?o:V},t}(R),te=function(r){v(t,r);function t(e){var n=r.call(this)||this;return n._value=e,n}return Object.defineProperty(t.prototype,"value",{get:function(){return this.getValue()},enumerable:!1,configurable:!0}),t.prototype._subscribe=function(e){var n=r.prototype._subscribe.call(this,e);return!n.closed&&e.next(this._value),n},t.prototype.getValue=function(){var e=this,n=e.hasError,o=e.thrownError,s=e._value;if(n)throw o;return this._throwIfClosed(),s},t.prototype.next=function(e){r.prototype.next.call(this,this._value=e)},t}(R),re=Object.getOwnPropertyDescriptor,ne=(r,t,e,n)=>{for(var o=n>1?void 0:n?re(t,e):t,s=r.length-1,i;s>=0;s--)(i=r[s])&&(o=i(o)||o);return o};exports.LivenessService=class{constructor(t){this.ngZone=t,this.stateSubject=new te(null),this.state$=this.stateSubject.asObservable()}init(t){this.ngZone.runOutsideAngular(()=>{this.engine=new m.LivenessEngine({...t,onStateChange:e=>{this.ngZone.run(()=>this.stateSubject.next(e))}}),this.engine.loadModels()})}attach(t){var e;(e=this.engine)==null||e.attachVideo(t)}start(){var t;(t=this.engine)==null||t.start()}reset(){var t;(t=this.engine)==null||t.reset()}ngOnDestroy(){var t;(t=this.engine)==null||t.stop()}};exports.LivenessService=ne([u.Injectable({providedIn:"root"})],exports.LivenessService);var oe=Object.defineProperty,se=Object.getOwnPropertyDescriptor,a=(r,t,e,n)=>{for(var o=n>1?void 0:n?se(t,e):t,s=r.length-1,i;s>=0;s--)(i=r[s])&&(o=(n?i(t,e,o):i(o))||o);return n&&o&&oe(t,e,o),o};exports.LivenessComponent=class{constructor(t){this.liveness=t,this.duration=60,this.containerClass="",this.videoWrapperClass="",this.videoClass="",this.timerClass="",this.stateClass="",this.challengeTextClass="",this.buttonClass="",this.retryButtonClass="",this.statusOverlayClass="",this.successMessageClass="",this.errorMessageClass="",this.instructionBoxClass="",this.successMessage="Verification Successful!",this.errorMessage="Verification failed. Please try again.",this.retryButtonLabel="Try Again",this.startButtonLabel="Start Verification",this.challengeMapping={Smile:"Smile",Blink:"Blink",Turn_Head:"Turn Head",Thumbs_Up:"Thumbs Up"},this.onComplete=new u.EventEmitter,this.onError=new u.EventEmitter,this.onStateChange=new u.EventEmitter}ngOnInit(){this.liveness.state$.subscribe(t=>{this.onStateChange.emit(t)})}async ngAfterViewInit(){try{const t=await navigator.mediaDevices.getUserMedia({video:{width:640,height:480,facingMode:"user"}}),e=this.webcamRef.nativeElement;e.srcObject=t,e.onloadedmetadata=()=>{e.play(),this.liveness.init({apiUrl:this.apiUrl,duration:this.duration,smileThreshold:this.smileThreshold,blinkThreshold:this.blinkThreshold,minturnHeadThreshold:this.minturnHeadThreshold,maxturnHeadThreshold:this.maxturnHeadThreshold,onComplete:n=>this.onComplete.emit(n),onError:n=>this.onError.emit(n)}),this.liveness.attach(e)}}catch{this.onError.emit({success:!1,reason:"Camera access denied"})}}ngOnDestroy(){var e,n;const t=(n=(e=this.webcamRef)==null?void 0:e.nativeElement)==null?void 0:n.srcObject;t==null||t.getTracks().forEach(o=>o.stop())}};a([u.ViewChild("webcam")],exports.LivenessComponent.prototype,"webcamRef",2);a([u.Input()],exports.LivenessComponent.prototype,"apiUrl",2);a([u.Input()],exports.LivenessComponent.prototype,"duration",2);a([u.Input()],exports.LivenessComponent.prototype,"smileThreshold",2);a([u.Input()],exports.LivenessComponent.prototype,"blinkThreshold",2);a([u.Input()],exports.LivenessComponent.prototype,"minturnHeadThreshold",2);a([u.Input()],exports.LivenessComponent.prototype,"maxturnHeadThreshold",2);a([u.Input()],exports.LivenessComponent.prototype,"containerClass",2);a([u.Input()],exports.LivenessComponent.prototype,"videoWrapperClass",2);a([u.Input()],exports.LivenessComponent.prototype,"videoClass",2);a([u.Input()],exports.LivenessComponent.prototype,"timerClass",2);a([u.Input()],exports.LivenessComponent.prototype,"stateClass",2);a([u.Input()],exports.LivenessComponent.prototype,"challengeTextClass",2);a([u.Input()],exports.LivenessComponent.prototype,"buttonClass",2);a([u.Input()],exports.LivenessComponent.prototype,"retryButtonClass",2);a([u.Input()],exports.LivenessComponent.prototype,"statusOverlayClass",2);a([u.Input()],exports.LivenessComponent.prototype,"successMessageClass",2);a([u.Input()],exports.LivenessComponent.prototype,"errorMessageClass",2);a([u.Input()],exports.LivenessComponent.prototype,"instructionBoxClass",2);a([u.Input()],exports.LivenessComponent.prototype,"successMessage",2);a([u.Input()],exports.LivenessComponent.prototype,"errorMessage",2);a([u.Input()],exports.LivenessComponent.prototype,"retryButtonLabel",2);a([u.Input()],exports.LivenessComponent.prototype,"startButtonLabel",2);a([u.Input()],exports.LivenessComponent.prototype,"challengeMapping",2);a([u.Output()],exports.LivenessComponent.prototype,"onComplete",2);a([u.Output()],exports.LivenessComponent.prototype,"onError",2);a([u.Output()],exports.LivenessComponent.prototype,"onStateChange",2);exports.LivenessComponent=a([u.Component({selector:"LivenessCheck",standalone:!0,imports:[q.CommonModule],templateUrl:"./liveness.component.html",encapsulation:u.ViewEncapsulation.None})],exports.LivenessComponent);exports.verifyLiveness=k.verifyLiveness;exports.LivenessEngine=m.LivenessEngine;exports.LivenessSDK=m.LivenessSDK;exports.useLiveness=m.useLiveness;
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { verifyLiveness as mt } from "./api-BpiDoGOd.js";
|
|
2
|
-
import { L as Z } from "./LivenessCheck-
|
|
3
|
-
import { a as St, u as _t } from "./LivenessCheck-
|
|
2
|
+
import { L as Z } from "./LivenessCheck-CtndKzVw.js";
|
|
3
|
+
import { a as St, u as _t } from "./LivenessCheck-CtndKzVw.js";
|
|
4
4
|
import { Injectable as W, ViewChild as K, Input as c, Output as j, Component as q, ViewEncapsulation as G, EventEmitter as _ } from "@angular/core";
|
|
5
5
|
import { CommonModule as J } from "@angular/common";
|
|
6
6
|
var E = function(e, r) {
|
package/dist/react.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./LivenessCheck-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./LivenessCheck-6oh9vnb0.cjs");require("react-webcam");exports.LivenessSDK=e.LivenessSDK;
|
package/dist/react.js
CHANGED