@hexar/biometric-identity-sdk-core 1.2.1 → 1.4.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/dist/BiometricIdentitySDK.js +8 -4
- package/dist/api/BackendClient.js +5 -1
- package/dist/encryption/index.d.ts +1 -1
- package/dist/encryption/index.js +2 -2
- package/package.json +1 -1
- package/src/BiometricIdentitySDK.ts +15 -11
- package/src/api/BackendClient.ts +6 -5
- package/src/encryption/index.ts +2 -2
|
@@ -286,7 +286,7 @@ class BiometricIdentitySDK {
|
|
|
286
286
|
const MIN_FRAMES = 10; // Minimum frames required for profile picture validation (backend warns if < 10)
|
|
287
287
|
if (validFrames.length < MIN_FRAMES) {
|
|
288
288
|
logger_1.logger.error(`Insufficient valid frames: ${validFrames.length} < ${MIN_FRAMES}`);
|
|
289
|
-
throw this.createError(types_1.BiometricErrorCode.
|
|
289
|
+
throw this.createError(types_1.BiometricErrorCode.CAMERA_NOT_AVAILABLE, 'Camera capture failed. Please ensure good lighting and try again.');
|
|
290
290
|
}
|
|
291
291
|
/**
|
|
292
292
|
* Perform backend validation
|
|
@@ -379,7 +379,11 @@ class BiometricIdentitySDK {
|
|
|
379
379
|
minimumRequired: 10
|
|
380
380
|
});
|
|
381
381
|
}
|
|
382
|
-
|
|
382
|
+
// 15 frames gives the backend enough temporal spread to reliably detect
|
|
383
|
+
// blink (EAR variation) and head movement across the 8-second recording.
|
|
384
|
+
// The previous value of 5 was too low: at ~0.6 FPS a blink event
|
|
385
|
+
// (150–300 ms) was statistically unlikely to be captured in any frame.
|
|
386
|
+
const MAX_FRAMES = 15;
|
|
383
387
|
if (videoFrames.length > MAX_FRAMES) {
|
|
384
388
|
const step = Math.floor(videoFrames.length / MAX_FRAMES);
|
|
385
389
|
videoFrames = videoFrames.filter((_, index) => index % step === 0).slice(0, MAX_FRAMES);
|
|
@@ -410,10 +414,10 @@ class BiometricIdentitySDK {
|
|
|
410
414
|
const compressedFrame = this.fixBase64Padding(await this.compressImage(frame));
|
|
411
415
|
validFrames.push(compressedFrame);
|
|
412
416
|
}
|
|
413
|
-
const MIN_FRAMES = 5;
|
|
417
|
+
const MIN_FRAMES = 5;
|
|
414
418
|
if (validFrames.length < MIN_FRAMES) {
|
|
415
419
|
logger_1.logger.error(`Insufficient valid frames: ${validFrames.length} < ${MIN_FRAMES}`);
|
|
416
|
-
throw new Error(
|
|
420
|
+
throw new Error('Insufficient video frames captured. Please try again.');
|
|
417
421
|
}
|
|
418
422
|
logger_1.logger.info('Sending validation request to backend', {
|
|
419
423
|
framesCount: validFrames.length,
|
|
@@ -3,8 +3,12 @@
|
|
|
3
3
|
* Backend API Client for Biometric Identity SDK
|
|
4
4
|
* Communicates with the Python backend for AI-powered validation
|
|
5
5
|
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
6
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
10
|
exports.BackendClient = void 0;
|
|
11
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
8
12
|
const logger_1 = require("../utils/logger");
|
|
9
13
|
/**
|
|
10
14
|
* Client for communicating with the Biometric Identity Backend
|
|
@@ -60,7 +64,7 @@ class BackendClient {
|
|
|
60
64
|
});
|
|
61
65
|
}
|
|
62
66
|
generateSDKSessionId() {
|
|
63
|
-
return `sdk-${
|
|
67
|
+
return `sdk-${crypto_1.default.randomBytes(16).toString('hex')}`;
|
|
64
68
|
}
|
|
65
69
|
/**
|
|
66
70
|
* Compare faces between document and live capture
|
|
@@ -35,4 +35,4 @@ export declare function encryptImages(images: string[], encryptionKey?: string):
|
|
|
35
35
|
/**
|
|
36
36
|
* Create integrity signature for data
|
|
37
37
|
*/
|
|
38
|
-
export declare function createIntegritySignature(data: any): string;
|
|
38
|
+
export declare function createIntegritySignature(data: any, key: string): string;
|
package/dist/encryption/index.js
CHANGED
|
@@ -90,10 +90,10 @@ async function encryptImages(images, encryptionKey) {
|
|
|
90
90
|
/**
|
|
91
91
|
* Create integrity signature for data
|
|
92
92
|
*/
|
|
93
|
-
function createIntegritySignature(data) {
|
|
93
|
+
function createIntegritySignature(data, key) {
|
|
94
94
|
const dataString = JSON.stringify(data);
|
|
95
95
|
return crypto_1.default
|
|
96
|
-
.createHmac('sha256',
|
|
96
|
+
.createHmac('sha256', key)
|
|
97
97
|
.update(dataString)
|
|
98
98
|
.digest('hex');
|
|
99
99
|
}
|
package/package.json
CHANGED
|
@@ -376,8 +376,8 @@ export class BiometricIdentitySDK {
|
|
|
376
376
|
if (validFrames.length < MIN_FRAMES) {
|
|
377
377
|
logger.error(`Insufficient valid frames: ${validFrames.length} < ${MIN_FRAMES}`);
|
|
378
378
|
throw this.createError(
|
|
379
|
-
BiometricErrorCode.
|
|
380
|
-
|
|
379
|
+
BiometricErrorCode.CAMERA_NOT_AVAILABLE,
|
|
380
|
+
'Camera capture failed. Please ensure good lighting and try again.'
|
|
381
381
|
);
|
|
382
382
|
}
|
|
383
383
|
|
|
@@ -492,7 +492,11 @@ export class BiometricIdentitySDK {
|
|
|
492
492
|
});
|
|
493
493
|
}
|
|
494
494
|
|
|
495
|
-
|
|
495
|
+
// 15 frames gives the backend enough temporal spread to reliably detect
|
|
496
|
+
// blink (EAR variation) and head movement across the 8-second recording.
|
|
497
|
+
// The previous value of 5 was too low: at ~0.6 FPS a blink event
|
|
498
|
+
// (150–300 ms) was statistically unlikely to be captured in any frame.
|
|
499
|
+
const MAX_FRAMES = 15;
|
|
496
500
|
if (videoFrames.length > MAX_FRAMES) {
|
|
497
501
|
const step = Math.floor(videoFrames.length / MAX_FRAMES);
|
|
498
502
|
videoFrames = videoFrames.filter((_, index) => index % step === 0).slice(0, MAX_FRAMES);
|
|
@@ -501,12 +505,12 @@ export class BiometricIdentitySDK {
|
|
|
501
505
|
sampledCount: videoFrames.length
|
|
502
506
|
});
|
|
503
507
|
}
|
|
504
|
-
|
|
508
|
+
|
|
505
509
|
const compressedFrontImage = this.fixBase64Padding(await this.compressImage(this.state.frontID.data));
|
|
506
|
-
const compressedBackImage = this.state.backID?.data
|
|
510
|
+
const compressedBackImage = this.state.backID?.data
|
|
507
511
|
? this.fixBase64Padding(await this.compressImage(this.state.backID.data))
|
|
508
512
|
: undefined;
|
|
509
|
-
|
|
513
|
+
|
|
510
514
|
const validFrames: string[] = [];
|
|
511
515
|
for (let i = 0; i < videoFrames.length; i++) {
|
|
512
516
|
const frame = videoFrames[i];
|
|
@@ -514,25 +518,25 @@ export class BiometricIdentitySDK {
|
|
|
514
518
|
logger.warn(`Skipping invalid frame ${i}: not a string`);
|
|
515
519
|
continue;
|
|
516
520
|
}
|
|
517
|
-
|
|
521
|
+
|
|
518
522
|
if (frame.length < 100) {
|
|
519
523
|
logger.warn(`Skipping invalid frame ${i}: too short (${frame.length} chars), likely a file path`);
|
|
520
524
|
continue;
|
|
521
525
|
}
|
|
522
|
-
|
|
526
|
+
|
|
523
527
|
if (!this.isValidBase64(frame)) {
|
|
524
528
|
logger.warn(`Skipping invalid frame ${i}: not valid base64`);
|
|
525
529
|
continue;
|
|
526
530
|
}
|
|
527
|
-
|
|
531
|
+
|
|
528
532
|
const compressedFrame = this.fixBase64Padding(await this.compressImage(frame));
|
|
529
533
|
validFrames.push(compressedFrame);
|
|
530
534
|
}
|
|
531
535
|
|
|
532
|
-
const MIN_FRAMES = 5;
|
|
536
|
+
const MIN_FRAMES = 5;
|
|
533
537
|
if (validFrames.length < MIN_FRAMES) {
|
|
534
538
|
logger.error(`Insufficient valid frames: ${validFrames.length} < ${MIN_FRAMES}`);
|
|
535
|
-
throw new Error(
|
|
539
|
+
throw new Error('Insufficient video frames captured. Please try again.');
|
|
536
540
|
}
|
|
537
541
|
|
|
538
542
|
logger.info('Sending validation request to backend', {
|
package/src/api/BackendClient.ts
CHANGED
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
* Communicates with the Python backend for AI-powered validation
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
import crypto from 'crypto';
|
|
7
|
+
import {
|
|
8
|
+
ValidationResult,
|
|
9
|
+
VideoResult,
|
|
9
10
|
LivenessValidationResult,
|
|
10
11
|
DocumentData,
|
|
11
|
-
BiometricConfig
|
|
12
|
+
BiometricConfig
|
|
12
13
|
} from '../types';
|
|
13
14
|
import { logger } from '../utils/logger';
|
|
14
15
|
|
|
@@ -221,7 +222,7 @@ export class BackendClient {
|
|
|
221
222
|
}
|
|
222
223
|
|
|
223
224
|
private generateSDKSessionId(): string {
|
|
224
|
-
return `sdk-${
|
|
225
|
+
return `sdk-${crypto.randomBytes(16).toString('hex')}`;
|
|
225
226
|
}
|
|
226
227
|
|
|
227
228
|
/**
|
package/src/encryption/index.ts
CHANGED
|
@@ -99,10 +99,10 @@ export async function encryptImages(
|
|
|
99
99
|
/**
|
|
100
100
|
* Create integrity signature for data
|
|
101
101
|
*/
|
|
102
|
-
export function createIntegritySignature(data: any): string {
|
|
102
|
+
export function createIntegritySignature(data: any, key: string): string {
|
|
103
103
|
const dataString = JSON.stringify(data);
|
|
104
104
|
return crypto
|
|
105
|
-
.createHmac('sha256',
|
|
105
|
+
.createHmac('sha256', key)
|
|
106
106
|
.update(dataString)
|
|
107
107
|
.digest('hex');
|
|
108
108
|
}
|