UNPKG

@quadible/web-sdk

Version:

The web sdk for Quadible's behavioral authentication service.

157 lines 5.77 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const eventemitter2_1 = require("eventemitter2"); const FormData_1 = require("./FormData"); const sleep_1 = __importDefault(require("./sleep")); class WebcamSession extends eventemitter2_1.EventEmitter2 { api; worker; isStarted = false; isAuthenticatingFrame = false; isFaceAuthenticated = false; lastAuthResult = null; nextVideoFrame; consecutiveNoFaceCount = 0; consecutiveNoFaceThreshold = 2; failedFaceAuthTries = 0; failedFaceAuthRetryIntervalsMs = [0, 1e3, 1e3, 2e3, 2e3, 5e3, 5e3, 10e3]; lastTrackingUpdate = Date.now(); predictionHandler = ((newFrame) => { this.nextVideoFrame = newFrame; if (!this.isAuthenticatingFrame) { this.processNextFrame(); } }).bind(this); constructor(api, worker) { super(); this.api = api; this.worker = worker; } async start() { this.isStarted = true; await this.worker.init(); this.worker.on('predictions', this.predictionHandler); } async stop() { this.isStarted = false; this.worker.off('predictions', this.predictionHandler); } async processNextFrame() { try { this.isAuthenticatingFrame = true; while (true) { const frame = this.nextVideoFrame; this.nextVideoFrame = undefined; if (!frame) { break; } await this.processFrame(frame); } } finally { this.isAuthenticatingFrame = false; } } async processFrame(frame) { let hasFaces = Boolean(frame.predictions.length); if (hasFaces) { this.consecutiveNoFaceCount = 0; } else { this.consecutiveNoFaceCount++; if (this.consecutiveNoFaceCount <= this.consecutiveNoFaceThreshold) { hasFaces = true; } } if (!hasFaces) { // If we lost face and lockScreenOnFaceLost = true, mark as unauthorized this.sendTrackingEndIfNeeded(); this.setFaceAuthStatus(false); } else if (!this.isFaceAuthenticated) { // If just gained or regained a face, authenticate await (0, sleep_1.default)(this.getAuthRetryInterval()); const nextFrame = this.nextVideoFrame || frame; this.lastAuthResult = await this.authenticateFrame(nextFrame.imageBase64); this.setFaceAuthStatus(this.lastAuthResult.authenticated); this.incrementOrResetFaceAuthTries(); } else { // If we found a face and we were already authenticated, send tracking this.sendTrackingIfNeeded(); } } incrementOrResetFaceAuthTries() { if (this.isFaceAuthenticated) { this.failedFaceAuthTries = 0; } else { this.failedFaceAuthTries++; } } getAuthRetryInterval() { let interval = this.failedFaceAuthRetryIntervalsMs[this.failedFaceAuthTries]; if (isNaN(interval)) { interval = this.failedFaceAuthRetryIntervalsMs[this.failedFaceAuthRetryIntervalsMs.length - 1]; } return interval; } async authenticateFrame(base64DataUrl) { const result = await fetch(base64DataUrl); const formData = (0, FormData_1.createFormData)(); const fileBlob = await result.blob(); formData.append('file', fileBlob); const response = await (await this.api.postFile('/v1/face/authenticate', formData)).json(); this.emit("face-auth-response" /* WebcamSessionEvent.FaceAuthResponse */, response); return response; } setFaceAuthStatus(status) { const oldStatus = this.isFaceAuthenticated; this.isFaceAuthenticated = status; if (status && !oldStatus) { this.emit("face-auth" /* WebcamSessionEvent.FaceAuthenticated */); } if (!status && oldStatus) { this.emit("face-auth-lost" /* WebcamSessionEvent.FaceAuthenticationLost */); } if (status !== oldStatus) { this.emit("face-auth-change" /* WebcamSessionEvent.FaceAuthenticationStatusChanged */, { status, lastAuthResult: this.lastAuthResult }); } } sendTrackingEndIfNeeded() { if (this.isFaceAuthenticated) { this.api.pushEvents([{ kind: "facetracking" /* EventKind.FaceTracking */, timestamp: Date.now(), payload: { trackingId: this.lastAuthResult.trackingId, isTrackingActive: false } }]); this.emit("tracking-end-sent" /* WebcamSessionEvent.TrackingEndSent */); } } sendTrackingIfNeeded() { const now = Date.now(); if (this.lastTrackingUpdate + 2e3 < now) { this.lastTrackingUpdate = now; this.api.pushEvents([{ kind: "facetracking" /* EventKind.FaceTracking */, timestamp: Date.now(), payload: { trackingId: this.lastAuthResult.trackingId, isTrackingActive: true } }]); this.emit("tracking-sent" /* WebcamSessionEvent.TrackingSent */); } } } exports.default = WebcamSession; //# sourceMappingURL=WebcamSession.js.map