registerNewUserWithIdCard: async function()

in amplify/backend/function/idvworkflowfn/src/idvfunctions.js [302:458]


    registerNewUserWithIdCard: async function (userInfoAsJson, faceImageDataBase64, idImageDataBase64) {
        // 1. First check the face image quality via DetectFaces
        //    a. For face on id card
        //    b. For selfie
        // 2. Use CompareFaces to ensure that the face in captured image is the same as on the id card
        // 3. Use SearchFacesByImage against the collection(s) to check for any duplicate registration
        // 4. Index the face image using IndexFaces and use the ExternalImageId (userid, in this case)
        //    to associate the face embeddings with the ExternalImageId
        // 5. Store the face image in the S3 bucket along with the user metadata in DDB (this is already in place)

        // NOTE: In 'registerNewUserWithIdCard', we'll supply image blobs directly to the Rekognition APIs
        //       For details on how to supply S3-stored images to the Rekognition APIs, please see 'registerNewUser'

        const bucket = process.env.STORAGE_IDVIMAGEBUCKET_BUCKETNAME;
        const userInfoTable = process.env.API_AMAZONREKOGNITIONIDV_USERINFOTABLE_NAME;

        const userInfo = JSON.parse(userInfoAsJson);
        var response = {
            Companyid: userInfo.companyid,
            UserId: userInfo.userid,
            RegistrationStatus: 'incomplete',
            Success: true,
            Message: '',
        };

        const collectionId = await graphqlhelpers.getActiveCollection();
        if(!collectionId) {
            response.Success = false;
            response.Message = "Unable to fetch active collection";
            return response;
        }

        const rek = new Rekognition();
        try {
            var faceImageBlob = Buffer.from(faceImageDataBase64, 'base64');
            var idImageBlob = Buffer.from(idImageDataBase64, 'base64');

            var params = {
                Image: {
                    Bytes: faceImageBlob
                }
            };
            // 1a. Check the face image quality via DetectFaces
            var detectFacesResponse = await rek.detectFaces(params).promise();
            var detectFacesValidation = validateidv.validateDetectFacesResponse(detectFacesResponse);
            if (!detectFacesValidation.success) {
                response.Message = detectFacesValidation.message;
                response.RegistrationStatus = 'detectfaces-failed for face (*not* id card)';
                response.Success = false;
            }
            
            // 1b. Check the id card face image quality via DetectFaces
            if (response.Success) {
                params = {
                    Image: {
                        Bytes: idImageBlob
                    }
                };
                detectFacesResponse = await rek.detectFaces(params).promise();
                detectFacesValidation = validateidv.validateDetectFacesResponse(detectFacesResponse);
                if (!detectFacesValidation.success) {
                    response.Message = detectFacesValidation.message;
                    response.RegistrationStatus = 'detectfaces-failed for id card';
                    response.Success = false;
                }
            }
            
            // 2. Compare faces across id card and selfie
            if (response.Success) {
                params = {
                    SimilarityThreshold: 90,
                    SourceImage: {
                        Bytes: faceImageBlob
                    },
                    TargetImage: {
                        Bytes: idImageBlob
                    }
                };
                const compareFacesResponse = await rek.compareFaces(params).promise();
                const compareFacesValidation = validateidv.validateFaceComparison(compareFacesResponse);
                if(!compareFacesValidation.success) {
                    response.Message = compareFacesValidation.message;
                    response.RegistrationStatus = 'compare-faces validation failed';
                    response.Success = false;
                }
            }
            
            // 3. Use SearchFacesByImage against the collection(s) to check for any duplicate registration
            if(response.Success) {
                params = {
                    CollectionId: collectionId,
                    FaceMatchThreshold: 95,
                    Image: {
                        Bytes: faceImageBlob
                    }
                };

                const searchFacesResponse = await rek.searchFacesByImage(params).promise();
                const duplicateCheckResponse = validateidv.validateDuplicateCheck(searchFacesResponse);
                if (!duplicateCheckResponse.success) {
                    response.Message = duplicateCheckResponse.message;
                    response.RegistrationStatus = 'duplicate-found';
                    response.Success = false;
                }
            }
            
            var faceId = "";

            // 4. Index the face image using IndexFaces and use the ExternalImageId (userid, in this case)
            //    to associate the face embeddings with the ExternalImageId
            if (response.Success) {
                const externalImageId = userInfo.userid;
                params = {
                    CollectionId: collectionId,
                    DetectionAttributes: [],
                    ExternalImageId: externalImageId,
                    Image: {
                        Bytes: faceImageBlob
                    }
                }
                const indexFaceResponse = await rek.indexFaces(params).promise();
                if (!indexFaceResponse ||
                    !indexFaceResponse.FaceRecords ||
                    indexFaceResponse.FaceRecords.length != 1) {
                    response.Message = 'IndexFaces failed';
                    response.RegistrationStatus = 'indexfaces-failed';
                    response.Success = false;
                } else {
                    faceId = indexFaceResponse.FaceRecords[0].Face.FaceId;
                    response.RegistrationStatus = 'done';
                }
            }
            
            // 5. Now update ddb entry w/ face embeddings id, if successful so far
            // If prev failure, then update reg status in ddb
            if (response.Success) {
                const ddbResponse = await updateUserInfo(userInfoTable, userInfo, faceId, response.RegistrationStatus);
                if (!ddbResponse.success) {
                    response.Message = 'UserInfo ddb update failed!';
                    response.RegistrationStatus = 'userinfo-ddb-failed';
                    response.Success = false;
                }
                else {
                    response.Success = true;
                    response.Message = '';
                }
            }
        }
        catch (e) {
            response.Message = e.toString();
            response.RegistrationStatus = 'unknown-error';
            response.Success = false;
            console.log(e);
        }

        return response;
    },