@@ -40,37 +40,7 @@ const start = async function (identityId) {
4040} ;
4141
4242// Public: Verify the authentication by checking the score and session data
43- const verifyAuthentication = async function ( interviewId , token , candidate ) {
44- const session = await getSession ( interviewId ) ;
45-
46- // Prevents usage of session that doesn't exist.
47- if ( ! session ) {
48- return {
49- // Detailed debug message, in production you might want to avoid exposing internal details.
50- message : "No session found for interviewId " + interviewId ,
51- valid : false ,
52- } ;
53- }
54-
55- // Prevents reuse of the same session.
56- if ( session . status !== "pending" ) {
57- return {
58- // Detailed debug message, in production you might want to avoid exposing internal details.
59- message : "Session already used for interviewId " + interviewId ,
60- valid : false ,
61- } ;
62- }
63-
64- // Prevents usage of token from another interviewId.
65- if ( session . token !== token ) {
66- // Mark the session as rejected.
67- await updateSession ( interviewId , "rejected" ) ;
68- return {
69- // Detailed debug message, in production you might want to avoid exposing internal details.
70- message : "Token mismatch for interviewId " + interviewId ,
71- valid : false ,
72- } ;
73- }
43+ const getResults = async function ( interviewId , token , candidate ) {
7444
7545 // Prevents usage of candidate that doesn't match the identityId stored in session.
7646 if ( session . identityId !== candidate ) {
@@ -79,77 +49,71 @@ const verifyAuthentication = async function (interviewId, token, candidate) {
7949 return {
8050 // Detailed debug message, in production you might want to avoid exposing internal details.
8151 message : "identityId and candidate mismatch for interviewId " + interviewId ,
82- valid : false ,
52+ isValid : false ,
8353 } ;
8454 }
8555
86- // Finishing the session stop it from being changed further and triggers score calculation and business rules.
87- await finish ( token ) ; // Mark session as finished in Incode backend
56+ // Finishing the session triggers score calculation and business rules.
57+ await finishStatus ( token ) ; // Mark session as finished in Incode backend
58+ // Closing the session stop it from being changed, all /add/ endpoints will be rejected after this, and the score will be frozen.
59+ await setStatusClosed ( token ) ; // Mark session as closed in Incode backend
60+
8861
8962 let identityId , scoreStatus ;
9063 try {
9164 // At this point we already verified that the token matches, but
9265 // to be clear about our intentions, we use the token stored in the
9366 // database to get the identityId and compare it with the candidate.
94- const scoreResponse = await getScore ( session . token ) ;
67+ const scoreResponse = await getScore ( token ) ;
9568 identityId = scoreResponse . authentication . identityId ;
9669 scoreStatus = scoreResponse . overall . status ;
9770 } catch ( e ) {
98- // Mark the session as rejected.
99- await updateSession ( interviewId , "rejected" ) ;
10071 // If there is an error communicating with API, we consider validation failed.
10172 return {
10273 // Detailed debug message, in production you might want to avoid exposing internal details.
10374 message : "Error validating authentication for interviewId " + interviewId + ": " + e . message ,
104- valid : false ,
75+ isValid : false ,
10576 } ;
10677 }
10778
10879 // renderFaceAuth returns candidate, which should match identityId from score,
10980 // this prevents tampering of the identityId in the frontend.
11081 if ( identityId !== candidate ) {
111- // Mark the session as rejected.
112- await updateSession ( interviewId , "rejected" ) ;
11382 return {
11483 // Detailed debug message, in production you might want to avoid exposing internal details.
11584 message : "Session data doesn't match for interviewId " + interviewId ,
116- valid : false ,
85+ isValid : false ,
11786 } ;
11887 }
11988
12089 // If backend score overall status is not OK, validation fails.
12190 if ( scoreStatus !== "OK" ) {
122- // Mark the session as rejected.
123- await updateSession ( interviewId , "rejected" ) ;
12491 return {
12592 // Detailed debug message, in production you might want to avoid exposing internal details.
12693 message : "Face Validation failed for interviewId " + interviewId ,
127- valid : false ,
94+ isValid : false ,
12895 } ;
12996 }
13097
131- // Mark the session as approved since all checks passed.
132- await updateSession ( interviewId , "approved" ) ;
133-
13498 // Only valid if all checks passed, we return the identityId that was validated.
13599 return {
136100 // Detailed debug message, in production you might want to avoid exposing internal details.
137101 message : "Face Validation succeeded for interviewId " + interviewId ,
138- valid : true ,
102+ isValid : true ,
139103 identityId : identityId ,
140104 } ;
141105} ;
142106
143107// Private: Calls Incode's `omni/finish-status` API mark the session as finished
144- const finish = async function ( token ) {
108+ const finishStatus = async function ( token ) {
145109 const url = `${ apiurl } /omni/finish-status` ;
146110
147111 let sessionHeaders = { ...defaultHeader } ;
148112 sessionHeaders [ "X-Incode-Hardware-Id" ] = token ;
149113
150114 let response ;
151115 try {
152- response = await fetch ( url , { method : "GET " , headers : sessionHeaders } ) ;
116+ response = await fetch ( url , { method : "POST" , body : "{} ", headers : sessionHeaders } ) ;
153117 if ( ! response . ok ) {
154118 throw new Error ( "Request failed with code " + response . status ) ;
155119 }
@@ -160,6 +124,27 @@ const finish = async function (token) {
160124 return { redirectionUrl, action } ;
161125} ;
162126
127+ // Private: Calls Incode's `omni/session/status/set?action=Closed` API to close the session
128+ const setStatusClosed = async function ( token ) {
129+ const url = `${ apiurl } /omni/session/status/set?action=Closed` ;
130+
131+ let sessionHeaders = { ...defaultHeader } ;
132+ sessionHeaders [ "X-Incode-Hardware-Id" ] = token ;
133+
134+ let response ;
135+ try {
136+ response = await fetch ( url , { method : "POST" , body : "{}" , headers : sessionHeaders } ) ;
137+ if ( ! response . ok ) {
138+ throw new Error ( "Request failed with code " + response . status ) ;
139+ }
140+ } catch ( e ) {
141+ throw new Error ( "HTTP Post Error: " + e . message ) ;
142+ }
143+ const results = await response . json ( ) ;
144+ console . log ( { results} ) ;
145+ return results ;
146+ } ;
147+
163148// Private: Call Incode's `omni/get/score` API to retrieve the score for the session
164149const getScore = async function ( token ) {
165150 const url = `${ apiurl } /omni/get/score` ;
@@ -226,92 +211,7 @@ const getScore = async function (token) {
226211 return score ;
227212} ;
228213
229- /** Helper functions for sessions saving and retrieval from IndexedDB,
230- * in production this should be handled with your backend or secure storage */
231-
232- // Local database helper functions using IndexedDB
233- const DB_NAME = "AuthenticationDB" ;
234- const DB_VERSION = 1 ;
235- const STORE_NAME = "sessions" ;
236-
237- // Initialize IndexedDB
238- function initDB ( ) {
239- return new Promise ( ( resolve , reject ) => {
240- const request = indexedDB . open ( DB_NAME , DB_VERSION ) ;
241-
242- request . onerror = ( ) => reject ( request . error ) ;
243- request . onsuccess = ( ) => resolve ( request . result ) ;
244214
245- request . onupgradeneeded = ( event ) => {
246- const db = event . target . result ;
247- if ( ! db . objectStoreNames . contains ( STORE_NAME ) ) {
248- const objectStore = db . createObjectStore ( STORE_NAME , { keyPath : "interviewId" } ) ;
249- objectStore . createIndex ( "interviewId" , "interviewId" , { unique : true } ) ;
250- }
251- } ;
252- } ) ;
253- }
254-
255- // Read a specific session from IndexedDB by interviewId
256- async function getSession ( interviewId ) {
257- const db = await initDB ( ) ;
258- return new Promise ( ( resolve , reject ) => {
259- const transaction = db . transaction ( [ STORE_NAME ] , "readonly" ) ;
260- const objectStore = transaction . objectStore ( STORE_NAME ) ;
261- const request = objectStore . get ( interviewId ) ;
262-
263- request . onsuccess = ( ) => resolve ( request . result ) ;
264- request . onerror = ( ) => reject ( request . error ) ;
265- } ) ;
266- }
267-
268- // Add a new session to the database
269- async function addSession ( interviewId , token , identityId ) {
270- const db = await initDB ( ) ;
271- return new Promise ( ( resolve , reject ) => {
272- const transaction = db . transaction ( [ STORE_NAME ] , "readwrite" ) ;
273- const objectStore = transaction . objectStore ( STORE_NAME ) ;
274- const session = {
275- interviewId,
276- token,
277- identityId,
278- status : "pending" ,
279- timestamp : new Date ( ) . toISOString ( ) ,
280- } ;
281- const request = objectStore . add ( session ) ;
282-
283- request . onsuccess = ( ) => resolve ( session ) ;
284- request . onerror = ( ) => reject ( request . error ) ;
285- } ) ;
286- }
287-
288- // Update validation status for a session
289- async function updateSession ( interviewId , status ) {
290-
291- if ( status !== "rejected" && status !== "approved" ) {
292- throw new Error ( "Invalid status. Must be 'rejected' or 'approved'." ) ;
293- }
294-
295- const db = await initDB ( ) ;
296- return new Promise ( ( resolve , reject ) => {
297- const transaction = db . transaction ( [ STORE_NAME ] , "readwrite" ) ;
298- const objectStore = transaction . objectStore ( STORE_NAME ) ;
299- const getRequest = objectStore . get ( interviewId ) ;
300-
301- getRequest . onsuccess = ( ) => {
302- const session = getRequest . result ;
303- if ( session ) {
304- session . status = status ;
305- const updateRequest = objectStore . put ( session ) ;
306- updateRequest . onsuccess = ( ) => resolve ( session ) ;
307- updateRequest . onerror = ( ) => reject ( updateRequest . error ) ;
308- } else {
309- resolve ( null ) ;
310- }
311- } ;
312- getRequest . onerror = ( ) => reject ( getRequest . error ) ;
313- } ) ;
314- }
315215
316- const exampleBackend = { start, verifyAuthentication }
216+ const exampleBackend = { start, getResults }
317217export default exampleBackend ;
0 commit comments