Office security is always a concern that needs to be properly addressed, especially for tech companies. But there aren’t a lot of great solutions out there. Key cards are easy to lose. Fobs can be lost or stolen as well. Enter the power of APIs!
This past week, I built an office security system using facial recognition. A facial recognition office security system means one less thing to bring with you every day! I also added a Dropbox integration so anyone on the team could easily add new hires to the system.
I present to you the Dropbox and TrueFace.ai Facial Recognition Security System. Let’s get started building yours!
Step 1: Connect to the Dropbox API
For this tutorial, you’ll use the Dropbox API for file management of a facial recognition security system.
Do the following to get the credentials to connect the Dropbox API:
1a. Create an account on Dropbox if you don’t already have one
1b. Create an application on the Developer App Console
1c. Grab your API secret, API Key and generated access token.
Then, add all three of these as variables to your program.
Pro Tip: If you set these up as environment variables, you don’t have to worry about accidentally sharing your API keys to the world when you upload your project to GitHub.
Step 2: Add Dropbox Webhooks to Your Application
The best part about using RapidAPI Webhooks to connect to Dropbox is that you receive the webhook events through a direct SSL socket from RapidAPI. This means that you can now test your webhook integration on localhost, while also automatically gaining added speed and security. You can learn more about RapidAPI Webhooks in our docs.
Unlike other API webhooks, Dropbox provides very little hard data with the webhook event. Instead, the webhook’s primary purpose is to alert your program that something has changed. Then, it is your job to use other API calls to determine what exactly has changed. This means that the code for the webhook is very simple. All you need to do is listen for the webhook and then, when the webhooks occurs, check if an image upload has been made.
rapid.listen('Dropbox', 'webhookEvent', { 'token': process.env.RAPIDAPI_TOKEN }) .on('join', () => { }) .on('message', (message) => { checkForUpload(); }) .on('error', (error) => { console.log(error); }) .on('close', (reason) => { });
This code may seem simple, and it is, but the beauty of it is that we can now handle checking if an image only when we know a Dropbox webhook event has occured.
Step 3: Check if an Image Has Been Uploaded
Now that you know a webhook event has occurred, you will need to confirm that a file has been uploaded to a Dropbox folder. Let’s use a folder called /office-employee-image-upload-folder to upload all of the employee images to.
With the folder you’ve created, you will need to track when files are changed. The way Dropbox allows you to do this is by using a cursor. A cursor is a string that is used to keep track of your current folder state. When a cursor is saved, it can then be used to retrieve delta entries that have been recorded since the cursor was originally saved. To save the cursor when your program is first started, call the getFolderContents function:
rapid.call('Dropbox', 'getFolderContents', { 'accessToken': process.env.RAPIDAPI_TOKEN, 'folderPath': '/office-employee-image-upload-folder' }).on('success', (payload)=>{ cursor = payload[0].cursor; files = payload[0].entries; }).on('error', (payload)=>{ console.log(payload); });
With the cursor of the folder saved, you will need another function that uses the cursor to check if delta entries have been recorded. I’m going to call this function checkForUpload, which will be called anytime a webhook event occurs.
Within your checkForUpload function, call paginateFolderContents. This function, when given a cursor, will return delta entries that have been recorded. The information returned will allow you to go through all of the newly uploaded files. Use these newly uploaded files to check if the employee is already in the system and handle their images accordingly. I’ve opted to use an array to keep track of the employees currently in the system. Based on if they’re in the system already, you will either create a new enrollment or update an existing enrollment. You can look at the logic in my code below:
function checkForUpload(){ rapid.call('Dropbox', 'paginateFolderContents', { 'accessToken': process.env.RAPIDAPI_TOKEN, 'cursor': cursor }).on('success', (payload)=>{ files = payload[0].entries; if(files.length > 0){ for(let i = 0; i < files.length; i++){ if(files[i]['.tag'] == 'file'){ path = files[i].path_lower filename = path.replace(/^.*[/]/, ''); // file name -> employee name ind = filename.indexOf('-'); name = filename.substring(0, ind); if(!employee_names.includes(name)){ console.log("ENROLL"); downloadFile(path).then(res => { let id = enroll_employee(filename, name); }).catch(res => { console.log(res); }); } else { downloadFile(path).then(res => { let employee_id = employee_ids[employee_names.indexOf(name)]; update_employee(filename, employee_id); }).catch(res => { console.log(res); }); } } } } }).on('error', (payload)=>{ /*YOUR CODE GOES HERE*/ }); }
One thing you might be wondering is, what if there are files in the folder before you ever start your program? This is a great edge case of your program! To handle this instance, instead of calling paginateFolderContents, when you call getFolderContents at the start of your program, you use the same logic to process the images that were already uploaded. This logic allows you to go through all of the files already in the Dropbox folder and create the enrollments for each employee. This functionality is especially important. If your program crashes, you can just restart the program and you won’t have to re-upload images for each employee.
https://giphy.com/gifs/season-3-the-simpsons-3×5-xT5LMyQOkWhX4HEvm0
Step 4: Download the Dropbox Images
In order to use the images with TrueFace.ai, you need to first download the files. There might be a more efficient way to pipe the image data directly to the TrueFace.ai API call, but for now this is how I was able to get it working. If you have a good way of taking the image information from Dropbox and directly call the TrueFace.ai API without downloading, comment your solution down below!
To download the files, copy the downloadFile code snippet from RapidAPI along with downloading the fs npm package:
function downloadFile(path_to_file){ return new Promise((resolve, reject) => { rapid.call('Dropbox', 'downloadFile', { 'accessToken': process.env.RAPIDAPI_TOKEN, 'filePath': path_to_file }).on('success', (payload)=>{ let filename = path_to_file.replace(/^.*[/]/, ''); let file = fs.createWriteStream(filename); let request = https.get(payload.file, function(response) { response.pipe(file); }); getCursor(); file.on('finish', function() { resolve('success'); }); }).on('error', (payload)=>{ reject(‘it didn’t work’); }); }); }
Step 5: Connect to the TrueFace.ai API
Now that you have set up the file management system, the next step is to add TrueFace.ai. I’ve decided to use TrueFace.ai as the facial recognition API because if has a feature called Spoof Detection. This feature helps make the recognition more secure, and you can learn more about it in step 7!
To get started withTrueFace.ai, first select a pricing plan.
The BASIC plan allows you to make 5,000 TrueFace.ai API calls a month for free. However, you will be charged an overage for any calls that you make over this quota. RapidAPI will email you when you have reached 85% and 100% of your quota. Should you need to make more that 5,000 calls you can select the PRO or ULTRA plans, but for building and testing your application, we recommend the BASIC plan.
Step 6: Create and Update Employee Enrollments
When an image is uploaded, you have two options to process it:
- If it is the first time an image has been uploaded for an employee, you will need to create a new enrollment for them.
- If an employee has already had an image uploaded, you’ll just need to update their existing enrollment.
Scenario 1: Create new employee enrollment
The first scenario, of creating an employee enrollment, is achieved by using the Enroll function. This is what the code looks like:
function enroll_employee(img_path, employee_name){ console.log('ENROLLING: ' + employee_name); console.log('IMG PATH: ' + img_path); let employee_id; unirest.post("https://trueface.p.mashape.com/enroll") .header("X-Mashape-Key", process.env.MASHAPE_TOKEN_2) .attach("img0", fs.createReadStream(img_path)) .field("name", employee_name) .end(function (result) { console.log(result.status, result.headers, result.body); employee_id = result.body.data.enrollment_id; if(result.body.data.enrollment_id == 'enrollment processed successfully'){ employee_names.push(employee_name); employee_ids.push(employee_id); } }); }
Scenario 2: Update an existing enrollment
When an image of an existing employee is uploaded, just use the Update Enrollment to update the employee’s enrollment like so:
function update_employee(img_path, employee_id){ console.log('UPDATING: ' + employee_id); console.log('IMG PATH: ' + img_path); unirest.put("https://trueface.p.mashape.com/enroll") .header("X-Mashape-Key", process.env.MASHAPE_TOKEN_2) .field("enrollment_id", employee_id) .attach("img0", fs.createReadStream(img_path)) .end(function (result) { console.log(result.status, result.headers, result.body); }); }
Step 7: Update the Collection of Employees
To create a security system that is able to identify a face, you will need to have a collection of employee enrollments. To do this, you’ll need to create a collection when your program is started by calling the Create Collection function:
unirest.post("https://trueface.p.mashape.com/collection") .header("X-Mashape-Key", process.env.MASHAPE_TOKEN_2) .header("Content-Type", "application/x-www-form-urlencoded") .header("Accept", "application/json") .send("name=Office Employees") .end(function (result) { console.log(result.status, result.headers, result.body); collection = result.headers.data.collection; });
Any time an employee is added or updated, you’ll also need to update the collection to include them in your Office Employee collection. Create a function called update_collection, that is passed the collection_id along with the enrollment_id of the employee you want to add or update. Your update_collection function will make use of the TrueFace.ai Update Collection function.
function update_collection(collection_id, enrollment_id){ unirest.put("https://trueface.p.mashape.com/collection") .header("X-Mashape-Key", process.env.MASHAPE_TOKEN_2) .header("Content-Type", "application/x-www-form-urlencoded") .header("Accept", "application/json") .send("collection_id="+collection_id) .send("enrollment_id="+enrollment_id) .end(function (result) { console.log(result.status, result.headers, result.body); }); }
Step 8: Identify Employees & Spoof Detection
The only thing left to do from here is to get the hardware and connect it with this program. When the hardware has seen a person and taken a picture, you can call an identify function with a path to the picture taken. Here’s the code on how to do that:
function identify(path_to_file){ unirest.post("https://trueface.p.mashape.com/spdetect") .header("X-Mashape-Key", "kkLAE9tdKfmshARl9UVANBrYk4RKp1xDfWFjsnimWVdTYzp6HS") .header("Content-Type", "multipart/form-data") .attach("img", fs.createReadStream(path_to_file)) .end(function (result) { console.log(result.status, result.headers, result.body); if(result.headers.data.class == 'real'){ unirest.post("https://trueface.p.mashape.com/identify") .header("X-Mashape-Key", "kkLAE9tdKfmshARl9UVANBrYk4RKp1xDfWFjsnimWVdTYzp6HS") .field("collection_id", collection) .attach("img", fs.createReadStream(path_to_file)) .end(function (result) { console.log(result.status, result.headers, result.body); console.log(result.headers.data.name); return true; }); } else { return false; } }); }
The identify function you created uses both the Spoof Detection function and the Identify function from TrueFace.ai.
You might be wondering, what is a spoof? A spoof is when someone is trying to use a picture of an employee to break into the office. This is the feature of TrueFace.ai that helps make it more secure to use. With TrueFace.ai, holding up a picture of an employee won’t be accepted for entry to the building.
After determining if the face is a spoof or not, then you can check if it is part of the office employee collection. If this person is part of the collection, then you return true and the security system hardware will open the door.
Conclusion
Through the power of APIs, you now have a security system which doesn’t require key cards or a fob! All you have to make sure you bring with you to work is your face to scan into the building.
If you’re interested in learning more about security solutions with APIs, we’ve got some great security APIs on the marketplace like Eversign, Common Passwords, and other facial recognition APIs!
Comment down below what you thought of the Dropbox and TrueFace.ai APIs being used together for a security system.
Brad says
I love the sliding door at the top.
Do you have the uploads directory locked to prevent people from deleting files? Images can go in, but they cannot come out. The only thing that should be able to happen is the image gets marked as “DENY”. Is there a counter on the door entry. If a face is there and doesn’t match it for a certain number of seconds, does it lock out that face? Does the door go into lockdown if x number of attempts have been made?
What would happen if the spoofed image was wrapped around an appropriately sized face… The image might have to be morphed.
Then I remember a scene in “Sneakers”.
“Does anyone know how to defeat a 10 digit keypad!”
“uh, hmm, yea, Okay, I will try that”.
[Kick hard at the door handle and busts the lock!]
The lock on my front door is not bumpable. I keep looking at my 6 foot plate glass window sitting 5 ft to the right next to it, and the glass sliding door at the back of my house.
Then I also remember all of the Type 1 and type 2 failures that seems to happen with facial recognition I interact with. If you have 4 people in your office, you are likely not going to run into 1 set of failures. If you have as many as 20, you will start hitting the other set of errors. Someone has to keep track of validation to make sure that the validated people are validating against the right people. How many times have you had a blank image come back and say “Is this Henrietta?”
Alex Walling says
Thanks for leaving a comment!
– I thought the sliding door gif was very funny.
– I don’t currently have the Dropbox directory locked as I am the only one who currently has access to the folder, but if I open it up to others within the company then I would think about reworking that functionality. The way I would do it, if I were to add that functionality, is to do the marked as “DENY” system like you mentioned. That way the system can still identify who the face is, but if the person no longer has access to enter they will be denied entry.
– If you’re implementing this, I would recommend using a counter to insure that if someone fails to get validated, then they are locked out for a period of time. When you’re creating this, you’ll need to think through different edge cases like if someone is constantly trying to access the door, an employee who has access fails to scan properly more than the counter limit and then loses access to the office, etc.
– I’m not sure how the morphing around a face would work. You can reach out to the team at TrueFace.ai for more information on the spoof detection!
– The same goes for the the failure points, I personally haven’t tested the API enough to have a comprehensive knowledge of limits and edge cases for the API. The team over at TrueFace.ai is amazing though, and they will be much more knowledgable about these sorts of questions! Their company actually started out as a company that provided hardware for facial recognition security systems, but they have since pivoted to provide the facial recognition engine instead, so they have plenty of experience in powering security systems through their facial recognition engine.
Perry says
Hi Alex,
i am looking for a solution that required a dropbox like account with facial recognition.
the use case is: upload batches of event photo’s and viewers would be able to only see pictures they are on. hence they would be excluded to see pictures where they are not on.
would you be able to help me witch such a solution? we could talk about $$ and revenue models later
thanks,
Perry
pjankie@hotmail.com