forked from kjanko/python-fingerprint-recognition
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
256 lines (197 loc) · 9.21 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
const express = require('express');
const multer = require('multer');
const { MongoClient } = require('mongodb');
const cors = require('cors');
const { spawn } = require('child_process')
const app = express();
const fs = require('fs');
require('dotenv').config();
const path = require('path');
const os = require('os');
const port = process.env.PORT || 5000;
const tempDir = os.tmpdir();
const corsOptions = {
origin: 'http://localhost:5173',
methods: ['GET', 'POST', 'PUT', 'DELETE'],
credentials: true,
allowedHeaders: ['Content-Type', 'Authorization'],
};
// Middleware
app.use(express.json({ limit: '50mb' }));
app.use(express.urlencoded({ limit: '50mb', extended: true }));
// Setup multer for handling multiple fields
const storage = multer.memoryStorage();
const upload = multer({ storage }).fields([
{ name: 'profilePhoto', maxCount: 1 },
]);
// Setup CORS to handle preflight requests for all routes
app.use(cors(corsOptions));
app.options('*', cors(corsOptions)); // Allow preflight for all routes
// MongoDB Connection URI
const client = new MongoClient(process.env.MONGODB_URI);
// Endpoint to handle multipart/form-data
app.post('/upload', upload, async (req, res) => {
console.log(req.body);
console.log("Request files:", req.files);
try {
// Handle the profile photo
const profilePhotoBuffer = req.files['profilePhoto'] ? req.files['profilePhoto'][0].buffer : null;
// Convert fingerprint image to base64 and validate if it exists
let fingerprintBase64;
if (req.body.fingerprintImage) {
fingerprintBase64 = req.body.fingerprintImage.replace(/^data:image\/png;base64,/, "");
if (!isValidBase64(fingerprintBase64)) {
return res.status(400).json({ message: 'Invalid fingerprint image format.' });
}
} else {
fingerprintBase64 = null;
}
// Spawn Python process
const pythonProcess = spawn('python', [path.join(__dirname, 'processor.py')]);
// Write the base64 fingerprint data to the Python process via stdin
pythonProcess.stdin.write(fingerprintBase64);
pythonProcess.stdin.end();
let dataBuffer = '';
let errorBuffer = '';
// Listen for data output (the descriptors) from the Python script
pythonProcess.stdout.on('data', (data) => {
dataBuffer += data.toString();
});
// Capture any error messages from stderr
pythonProcess.stderr.on('data', (error) => {
errorBuffer += error.toString();
});
// Once the stream ends, decide what to do based on the data received
pythonProcess.on('close', async (code) => {
if (errorBuffer) {
// If there is any error in stderr, return the error and skip the database insertion
console.error('Error in descriptor extraction:', errorBuffer);
return res.status(500).json({ message: 'Error in processing fingerprint', details: errorBuffer });
}
try {
// Parse the accumulated buffer as JSON
const descriptors = JSON.parse(dataBuffer);
console.log(descriptors);
// Only insert into MongoDB if there are no errors
const sampleData = {
firstName: req.body.firstName,
lastName: req.body.lastName,
middleName: req.body.middleName,
profilePhoto: profilePhotoBuffer, // Store image as Buffer
fingerprintDescriptors: descriptors, // Store only descriptors instead of fingerprint image
uploadedAt: new Date(),
};
// Connect to MongoDB and insert the data
await client.connect();
const database = client.db('designsbyese');
const collection = database.collection('samples');
// Insert data into MongoDB
const result = await collection.insertOne(sampleData);
console.log('Sample data stored:', result);
// Send success response with the inserted ID
res.status(200).json({ message: 'Sample uploaded successfully', id: result.insertedId });
} catch (e) {
console.error('Error parsing JSON or inserting data:', e);
res.status(500).json({ message: 'Error processing fingerprint descriptors' });
} finally {
await client.close();
}
});
} catch (error) {
console.error('Error uploading sample:', error);
res.status(500).json({ message: 'Error uploading sample', error: error.message });
}
});
// Function to check if a base64 string is valid
function isValidBase64(str) {
// Check if the string is a valid base64 encoded string
const regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
return regex.test(str);
}
app.post('/validatefingerprint', async (req, res) => {
console.log(req.body);
const { imageFile } = req.body;
if (!imageFile) {
return res.status(400).json({
message: 'No fingerprint image provided.',
});
}
try {
// Connect to MongoDB
await client.connect();
const database = client.db('designsbyese');
const collection = database.collection('samples');
// Retrieve all fingerprint descriptors and user data from MongoDB
const fingerprints = await collection.find({}, {
projection: { firstName: 1, lastName: 1, middleName: 1, profilePhoto: 1, fingerprintDescriptors: 1 }
}).toArray();
if (fingerprints.length === 0) {
return res.status(404).json({ message: 'No fingerprints found in the database.' });
}
// Write uploaded fingerprint to a temporary file
const uploadedFingerprintPath = path.join(tempDir, 'uploaded_fingerprint.png');
const base64Regex = /^data:image\/(?:png|jpeg|jpg);base64,/;
const base64Data = imageFile.replace(base64Regex, '');
// Save uploaded fingerprint as a binary .png file
await fs.promises.writeFile(uploadedFingerprintPath, base64Data, { encoding: 'base64' });
// Collect all stored fingerprint descriptors from the database
const storedDescriptors = fingerprints.map(fp => fp.fingerprintDescriptors);
// console.log(storedDescriptors)
// Write descriptors to a temporary file
const descriptorsFilePath = path.join(tempDir, 'descriptors.json');
await fs.promises.writeFile(descriptorsFilePath, JSON.stringify(storedDescriptors));
// Spawn Python process to compare fingerprints using descriptors
const pythonProcess = spawn('python', [path.join(__dirname, 'compare.py'), uploadedFingerprintPath, descriptorsFilePath]);
let dataFromPython = '';
pythonProcess.stdout.on('data', (data) => {
dataFromPython += data.toString();
});
pythonProcess.on('close', async (code) => {
if (code !== 0) {
console.error(`Python process exited with code ${code}`);
return res.status(500).json({ message: 'Error during fingerprint validation.' });
}
try {
const result = JSON.parse(dataFromPython);
console.log(result);
// Define a threshold for match percentage
const matchThreshold = 70;
// Handle the case when no match is found or the match percentage is below the threshold
if (result.matchIndex === -1 || result.matchPercentage === null || result.matchPercentage < 70) {
return res.status(404).json({
message: 'No fingerprint match found.',
});
}
const matchedUser = fingerprints[result.matchIndex];
// Return matched user details along with the match percentage
return res.json({
message: 'Fingerprint match found',
firstName: matchedUser.firstName,
lastName: matchedUser.lastName,
middleName: matchedUser.middleName,
profilePicture: matchedUser.profilePhoto,
matchPercentage: result.matchPercentage,
});
} catch (error) {
console.error('Error parsing Python output:', error);
return res.status(500).json({ message: 'Error parsing fingerprint match result.' });
}
});
pythonProcess.stderr.on('data', (data) => {
console.error(`Python error: ${data}`);
// Instead of returning a 500 status, treat as no match (Fingerprint mismatch)
return res.status(404).json({
message: 'No fingerprint match found.',
});
});
} catch (error) {
console.error('Error validating fingerprint:', error);
return res.status(500).json({ message: 'Error validating fingerprint. Please try again.' });
} finally {
await client.close();
}
});
// Start the server
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});