@hexar/biometric-identity-sdk-core 1.0.15 → 1.0.16

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.
@@ -89,6 +89,14 @@ export declare class BiometricIdentitySDK {
89
89
  * Compress image in browser environment using Canvas API
90
90
  */
91
91
  private compressImageBrowser;
92
+ /**
93
+ * Fix base64 padding issues
94
+ */
95
+ private fixBase64Padding;
96
+ /**
97
+ * Validate if string is valid base64
98
+ */
99
+ private isValidBase64;
92
100
  /**
93
101
  * Get current SDK state
94
102
  */
@@ -308,13 +308,34 @@ class BiometricIdentitySDK {
308
308
  sampledCount: videoFrames.length
309
309
  });
310
310
  }
311
- const compressedFrontImage = await this.compressImage(this.state.frontID.data);
311
+ const compressedFrontImage = this.fixBase64Padding(await this.compressImage(this.state.frontID.data));
312
312
  const compressedBackImage = this.state.backID?.data
313
- ? await this.compressImage(this.state.backID.data)
313
+ ? this.fixBase64Padding(await this.compressImage(this.state.backID.data))
314
314
  : undefined;
315
- const compressedFrames = await Promise.all(videoFrames.map(frame => this.compressImage(frame)));
315
+ const validFrames = [];
316
+ for (let i = 0; i < videoFrames.length; i++) {
317
+ const frame = videoFrames[i];
318
+ if (!frame || typeof frame !== 'string') {
319
+ logger_1.logger.warn(`Skipping invalid frame ${i}: not a string`);
320
+ continue;
321
+ }
322
+ if (frame.length < 100) {
323
+ logger_1.logger.warn(`Skipping invalid frame ${i}: too short (${frame.length} chars), likely a file path`);
324
+ continue;
325
+ }
326
+ if (!this.isValidBase64(frame)) {
327
+ logger_1.logger.warn(`Skipping invalid frame ${i}: not valid base64`);
328
+ continue;
329
+ }
330
+ const compressedFrame = this.fixBase64Padding(await this.compressImage(frame));
331
+ validFrames.push(compressedFrame);
332
+ }
333
+ if (validFrames.length < 10) {
334
+ logger_1.logger.error(`Insufficient valid frames: ${validFrames.length} < 10`);
335
+ throw new Error(`Insufficient valid video frames: ${validFrames.length} frames available, minimum 10 required`);
336
+ }
316
337
  logger_1.logger.info('Sending validation request to backend', {
317
- framesCount: compressedFrames.length,
338
+ framesCount: validFrames.length,
318
339
  duration: this.state.videoData.duration,
319
340
  challengesCount: this.state.videoData.challengesCompleted?.length || 0,
320
341
  frontImageSize: compressedFrontImage.length,
@@ -326,7 +347,7 @@ class BiometricIdentitySDK {
326
347
  const response = await this.backendClient.fullValidation({
327
348
  frontIdImage: compressedFrontImage,
328
349
  backIdImage: compressedBackImage,
329
- videoFrames: compressedFrames,
350
+ videoFrames: validFrames,
330
351
  videoDurationMs: this.state.videoData.duration,
331
352
  challengesCompleted: this.state.videoData.challengesCompleted || [],
332
353
  });
@@ -452,6 +473,35 @@ class BiometricIdentitySDK {
452
473
  img.src = `data:image/jpeg;base64,${base64Image}`;
453
474
  });
454
475
  }
476
+ /**
477
+ * Fix base64 padding issues
478
+ */
479
+ fixBase64Padding(base64) {
480
+ if (!base64)
481
+ return base64;
482
+ let cleaned = base64.replace(/\s/g, '');
483
+ if (cleaned.includes(',')) {
484
+ cleaned = cleaned.split(',')[1] || cleaned;
485
+ }
486
+ const padding = cleaned.length % 4;
487
+ if (padding > 0) {
488
+ cleaned += '='.repeat(4 - padding);
489
+ }
490
+ return cleaned;
491
+ }
492
+ /**
493
+ * Validate if string is valid base64
494
+ */
495
+ isValidBase64(str) {
496
+ if (!str || typeof str !== 'string')
497
+ return false;
498
+ const cleaned = str.replace(/\s/g, '');
499
+ if (cleaned.includes(',')) {
500
+ return true;
501
+ }
502
+ const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
503
+ return base64Regex.test(cleaned) && cleaned.length > 100;
504
+ }
455
505
  /**
456
506
  * Get current SDK state
457
507
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hexar/biometric-identity-sdk-core",
3
- "version": "1.0.15",
3
+ "version": "1.0.16",
4
4
  "description": "Core AI engine for biometric identity verification",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -391,16 +391,40 @@ export class BiometricIdentitySDK {
391
391
  });
392
392
  }
393
393
 
394
- const compressedFrontImage = await this.compressImage(this.state.frontID.data);
394
+ const compressedFrontImage = this.fixBase64Padding(await this.compressImage(this.state.frontID.data));
395
395
  const compressedBackImage = this.state.backID?.data
396
- ? await this.compressImage(this.state.backID.data)
396
+ ? this.fixBase64Padding(await this.compressImage(this.state.backID.data))
397
397
  : undefined;
398
- const compressedFrames = await Promise.all(
399
- videoFrames.map(frame => this.compressImage(frame))
400
- );
398
+
399
+ const validFrames: string[] = [];
400
+ for (let i = 0; i < videoFrames.length; i++) {
401
+ const frame = videoFrames[i];
402
+ if (!frame || typeof frame !== 'string') {
403
+ logger.warn(`Skipping invalid frame ${i}: not a string`);
404
+ continue;
405
+ }
406
+
407
+ if (frame.length < 100) {
408
+ logger.warn(`Skipping invalid frame ${i}: too short (${frame.length} chars), likely a file path`);
409
+ continue;
410
+ }
411
+
412
+ if (!this.isValidBase64(frame)) {
413
+ logger.warn(`Skipping invalid frame ${i}: not valid base64`);
414
+ continue;
415
+ }
416
+
417
+ const compressedFrame = this.fixBase64Padding(await this.compressImage(frame));
418
+ validFrames.push(compressedFrame);
419
+ }
420
+
421
+ if (validFrames.length < 10) {
422
+ logger.error(`Insufficient valid frames: ${validFrames.length} < 10`);
423
+ throw new Error(`Insufficient valid video frames: ${validFrames.length} frames available, minimum 10 required`);
424
+ }
401
425
 
402
426
  logger.info('Sending validation request to backend', {
403
- framesCount: compressedFrames.length,
427
+ framesCount: validFrames.length,
404
428
  duration: this.state.videoData.duration,
405
429
  challengesCount: this.state.videoData.challengesCompleted?.length || 0,
406
430
  frontImageSize: compressedFrontImage.length,
@@ -413,7 +437,7 @@ export class BiometricIdentitySDK {
413
437
  const response = await this.backendClient.fullValidation({
414
438
  frontIdImage: compressedFrontImage,
415
439
  backIdImage: compressedBackImage,
416
- videoFrames: compressedFrames,
440
+ videoFrames: validFrames,
417
441
  videoDurationMs: this.state.videoData.duration,
418
442
  challengesCompleted: this.state.videoData.challengesCompleted || [],
419
443
  });
@@ -563,6 +587,41 @@ export class BiometricIdentitySDK {
563
587
  });
564
588
  }
565
589
 
590
+ /**
591
+ * Fix base64 padding issues
592
+ */
593
+ private fixBase64Padding(base64: string): string {
594
+ if (!base64) return base64;
595
+
596
+ let cleaned = base64.replace(/\s/g, '');
597
+
598
+ if (cleaned.includes(',')) {
599
+ cleaned = cleaned.split(',')[1] || cleaned;
600
+ }
601
+
602
+ const padding = cleaned.length % 4;
603
+ if (padding > 0) {
604
+ cleaned += '='.repeat(4 - padding);
605
+ }
606
+
607
+ return cleaned;
608
+ }
609
+
610
+ /**
611
+ * Validate if string is valid base64
612
+ */
613
+ private isValidBase64(str: string): boolean {
614
+ if (!str || typeof str !== 'string') return false;
615
+
616
+ const cleaned = str.replace(/\s/g, '');
617
+ if (cleaned.includes(',')) {
618
+ return true;
619
+ }
620
+
621
+ const base64Regex = /^[A-Za-z0-9+/]*={0,2}$/;
622
+ return base64Regex.test(cleaned) && cleaned.length > 100;
623
+ }
624
+
566
625
  /**
567
626
  * Get current SDK state
568
627
  */