Skip to content

Commit caf75e2

Browse files
committed
Firebase functions
1 parent 2777b9e commit caf75e2

File tree

16 files changed

+6569
-34
lines changed

16 files changed

+6569
-34
lines changed

frontend/.firebaserc

Whitespace-only changes.

frontend/firebase.json

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,29 @@
5454
]
5555
}
5656
]
57-
}
57+
},
58+
"emulators": {
59+
"functions": {
60+
"port": 5000
61+
},
62+
"firestore": {
63+
"port": 8080
64+
},
65+
"ui": {
66+
"enabled": true
67+
}
68+
},
69+
"functions": [
70+
{
71+
"source": "functions",
72+
"codebase": "default",
73+
"ignore": [
74+
"node_modules",
75+
".git",
76+
"firebase-debug.log",
77+
"firebase-debug.*.log",
78+
"*.local"
79+
]
80+
}
81+
]
5882
}

frontend/functions/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules/
2+
*.local

frontend/functions/index.js

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/**
2+
* Import function triggers from their respective submodules:
3+
*
4+
* const {onCall} = require("firebase-functions/v2/https");
5+
* const {onDocumentWritten} = require("firebase-functions/v2/firestore");
6+
*
7+
* See a full list of supported triggers at https://firebase.google.com/docs/functions
8+
*/
9+
//
10+
// const {onRequest} = require('firebase-functions/v2/https');
11+
// const logger = require('firebase-functions/logger');
12+
//
13+
// Create and deploy your first functions
14+
// https://firebase.google.com/docs/functions/get-started
15+
//
16+
// exports.helloWorld = onRequest((request, response) => {
17+
// logger.info('Hello logs!', {structuredData: true});
18+
// response.send('Hello from Firebase!');
19+
// });
20+
21+
const admin = require('firebase-admin');
22+
const functions = require('firebase-functions');
23+
24+
admin.initializeApp();
25+
26+
const allowedPublicKeys = new Set([
27+
'publicKey1Base64Encoded',
28+
'publicKey2Base64Encoded',
29+
// Add more as needed
30+
]);
31+
32+
function validateSignature(data, signature, publicKeyBase64) {
33+
34+
return true;
35+
}
36+
37+
exports.handleValidationAndStore = functions.region('us-central1').https.onCall(async (data, context) => {
38+
console.log('Received data:', data);
39+
const {publicKey, data: inputData, signature} = data;
40+
41+
// Check if the publicKey is in the allowed set
42+
if (!allowedPublicKeys.has(publicKey)) {
43+
throw new functions.https.HttpsError('permission-denied', 'Public key not authorized');
44+
}
45+
46+
// Rate limiting based on public key
47+
const rateLimitRef = admin.firestore().collection('publicKeyRateLimits').doc(publicKey);
48+
49+
try {
50+
await admin.firestore().runTransaction(async (transaction) => {
51+
const doc = await transaction.get(rateLimitRef);
52+
const now = Date.now();
53+
const cutoff = now - 15 * 1000; // 15 seconds ago
54+
55+
if (doc.exists) {
56+
const lastCall = doc.data().lastCall;
57+
if (lastCall > cutoff) {
58+
throw new functions.https.HttpsError('resource-exhausted', 'Rate limit exceeded for this public key');
59+
}
60+
}
61+
62+
transaction.set(rateLimitRef, {lastCall: now}, {merge: true});
63+
});
64+
65+
// Validate signature
66+
if (!validateSignature(inputData, signature, publicKey)) {
67+
throw new functions.https.HttpsError('unauthenticated', 'Signature validation failed');
68+
}
69+
70+
// Store data in 'heartbeat' collection
71+
await admin.firestore().collection('heartbeat').add(inputData);
72+
73+
return {message: 'Data validated and stored successfully'};
74+
} catch (error) {
75+
console.error('Error during data validation and storage:', error);
76+
if (error instanceof functions.https.HttpsError) {
77+
throw error; // Re-throw HttpsError for Firebase Functions to handle
78+
}
79+
throw new functions.https.HttpsError('internal', 'An error occurred during validation or storage');
80+
}
81+
});

0 commit comments

Comments
 (0)