Skip to content

Commit 0221a02

Browse files
committed
Fix build errors
1 parent 7f1fda9 commit 0221a02

File tree

5 files changed

+138
-151
lines changed

5 files changed

+138
-151
lines changed

frontend/functions/build.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,21 @@ const keysFilePath = path.resolve(__dirname, 'allowed_keys.txt');
55
let keys = [];
66

77
if (fs.existsSync(keysFilePath)) {
8-
keys = fs.readFileSync(keysFilePath, 'utf-8')
9-
.split('\n')
10-
.map(key => key.trim())
11-
.filter(key => key.length > 0);
8+
keys = fs.readFileSync(keysFilePath, 'utf-8')
9+
.split('\n')
10+
.map(key => key.trim())
11+
.filter(key => key.length > 0);
1212

13-
const validatorFilePath = path.resolve(__dirname, 'functions/submitterValidator.ts');
14-
let validatorFileContent = fs.readFileSync(validatorFilePath, 'utf-8');
13+
const validatorFilePath = path.resolve(__dirname, 'functions/submitterValidator.ts');
14+
let validatorFileContent = fs.readFileSync(validatorFilePath, 'utf-8');
1515

16-
const keysSetString = keys.map(key => `'${key}'`).join(',\n ');
17-
validatorFileContent = validatorFileContent.replace(
18-
'// ALLOWED_PUBLIC_KEYS_PLACEHOLDER',
19-
keysSetString
20-
);
16+
const keysSetString = keys.map(key => `'${key}'`).join(',\n ');
17+
validatorFileContent = validatorFileContent.replace(
18+
'// ALLOWED_PUBLIC_KEYS_PLACEHOLDER',
19+
keysSetString,
20+
);
2121

22-
fs.writeFileSync(validatorFilePath, validatorFileContent);
22+
fs.writeFileSync(validatorFilePath, validatorFileContent);
2323
} else {
24-
console.warn('allowed_keys.txt not found. All submitters will be allowed.');
24+
console.warn('allowed_keys.txt not found. All submitters will be allowed.');
2525
}

frontend/functions/package-lock.json

Lines changed: 15 additions & 38 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/functions/package.json

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,26 @@
22
"name": "functions",
33
"description": "Cloud Functions for Firebase",
44
"scripts": {
5-
"serve": "firebase emulators:start --only functions",
5+
"serve": "npm run build && firebase emulators:start --only functions",
66
"shell": "firebase functions:shell",
7-
"start": "npm run build && node dist/index.js",
7+
"start": "npm run build && node lib/index.js",
88
"deploy": "firebase deploy --only functions",
99
"logs": "firebase functions:log",
1010
"test": "jest",
1111
"test:watch": "jest --watch",
12-
"build": "node build.js && tsc",
12+
"build": "node build.js && tsc -p tsconfig.json",
1313
"build:watch": "tsc --watch"
1414
},
1515
"engines": {
16-
"node": "18"
16+
"node": "22"
1717
},
18-
"main": "src/index.ts",
18+
"type": "commonjs",
19+
"main": "lib/index.js",
1920
"dependencies": {
2021
"blake2": "^5.0.0",
2122
"bs58check": "^3.0.1",
2223
"firebase-admin": "^12.1.0",
23-
"firebase-functions": "^5.0.0",
24+
"firebase-functions": "^6.2.0",
2425
"mina-signer": "^3.0.7"
2526
},
2627
"devDependencies": {

frontend/functions/src/index.ts

Lines changed: 93 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@ import * as blake2 from 'blake2';
44
import bs58check from 'bs58check';
55
import Client from 'mina-signer';
66
import { submitterAllowed } from './submitterValidator';
7+
import { CallableRequest, onCall } from 'firebase-functions/v2/https';
78

89
interface SignatureJson {
9-
field: string;
10-
scalar: string;
10+
field: string;
11+
scalar: string;
1112
}
1213

1314
interface HeartbeatData {
14-
publicKey: string;
15-
data: string;
16-
signature: SignatureJson;
15+
publicKey: string;
16+
data: string;
17+
signature: SignatureJson;
1718
}
1819

1920
const minaClient = new Client({ network: 'testnet' });
@@ -24,101 +25,103 @@ admin.initializeApp();
2425
const HEARTBEAT_RATE_LIMIT_MS = 15000;
2526

2627
function validateSignature(
27-
data: string,
28-
signature: SignatureJson,
29-
publicKeyBase58: string
28+
data: string,
29+
signature: SignatureJson,
30+
publicKeyBase58: string,
3031
): boolean {
32+
try {
33+
const h = blake2.createHash('blake2b', { digestLength: 32 });
34+
h.update(Buffer.from(data));
35+
const digest: string = h.digest().toString('hex');
36+
3137
try {
32-
const h = blake2.createHash('blake2b', { digestLength: 32 });
33-
h.update(Buffer.from(data));
34-
const digest: string = h.digest().toString('hex');
35-
36-
try {
37-
// TODO: remove this validation later, since the list is
38-
// hardcoded and we check that the key is there,
39-
// we know it is valid.
40-
let publicKeyBytes: Uint8Array;
41-
try {
42-
publicKeyBytes = bs58check.decode(publicKeyBase58);
43-
} catch (e) {
44-
console.error('Failed to decode public key:', e);
45-
return false;
46-
}
47-
48-
if (publicKeyBytes[0] !== 0xcb) {
49-
console.error('Invalid public key prefix');
50-
return false;
51-
}
52-
53-
return minaClient.verifyMessage({
54-
data: digest,
55-
signature,
56-
publicKey: publicKeyBase58,
57-
});
58-
} catch (e) {
59-
console.error('Error parsing signature or verifying:', e);
60-
return false;
61-
}
62-
} catch (e) {
63-
console.error('Error in signature validation:', e);
38+
// TODO: remove this validation later, since the list is
39+
// hardcoded and we check that the key is there,
40+
// we know it is valid.
41+
let publicKeyBytes: Uint8Array;
42+
try {
43+
publicKeyBytes = bs58check.decode(publicKeyBase58);
44+
} catch (e) {
45+
console.error('Failed to decode public key:', e);
6446
return false;
47+
}
48+
49+
if (publicKeyBytes[0] !== 0xcb) {
50+
console.error('Invalid public key prefix');
51+
return false;
52+
}
53+
54+
return minaClient.verifyMessage({
55+
data: digest,
56+
signature,
57+
publicKey: publicKeyBase58,
58+
});
59+
} catch (e) {
60+
console.error('Error parsing signature or verifying:', e);
61+
return false;
6562
}
63+
} catch (e) {
64+
console.error('Error in signature validation:', e);
65+
return false;
66+
}
6667
}
6768

68-
export const handleValidationAndStore = functions
69-
.region('us-central1')
70-
.https.onCall(async (data: HeartbeatData, context: functions.https.CallableContext) => {
71-
console.log('Received data:', data);
72-
const { publicKey, data: inputData, signature } = data;
69+
export const handleValidationAndStore = onCall(
70+
{ region: 'us-central1' },
71+
async (request: CallableRequest<HeartbeatData>) => {
72+
console.log('Received data:', request.data);
73+
const data = request.data;
74+
const { publicKey, data: inputData, signature } = data;
75+
76+
if (!submitterAllowed(publicKey)) {
77+
throw new functions.https.HttpsError(
78+
'permission-denied',
79+
'Public key not authorized',
80+
);
81+
}
7382

74-
if (!submitterAllowed(publicKey)) {
75-
throw new functions.https.HttpsError(
76-
'permission-denied',
77-
'Public key not authorized'
78-
);
79-
}
83+
const rateLimitRef = admin.firestore().collection('publicKeyRateLimits').doc(publicKey);
8084

81-
const rateLimitRef = admin.firestore().collection('publicKeyRateLimits').doc(publicKey);
82-
83-
try {
84-
await admin.firestore().runTransaction(async (transaction) => {
85-
const doc = await transaction.get(rateLimitRef);
86-
const now = Date.now();
87-
const cutoff = now - HEARTBEAT_RATE_LIMIT_MS;
88-
89-
if (doc.exists) {
90-
const lastCall = doc.data()?.['lastCall'];
91-
if (lastCall > cutoff) {
92-
throw new functions.https.HttpsError(
93-
'resource-exhausted',
94-
'Rate limit exceeded for this public key'
95-
);
96-
}
97-
}
98-
99-
transaction.set(rateLimitRef, { lastCall: now }, { merge: true });
100-
});
101-
102-
if (!validateSignature(inputData, signature, publicKey)) {
103-
throw new functions.https.HttpsError(
104-
'unauthenticated',
105-
'Signature validation failed'
106-
);
107-
}
108-
109-
await admin.firestore().collection('heartbeat').add(data);
110-
111-
return { message: 'Data validated and stored successfully' };
112-
} catch (error) {
113-
console.error('Error during data validation and storage:', error);
114-
if (error instanceof functions.https.HttpsError) {
115-
throw error;
116-
}
85+
try {
86+
await admin.firestore().runTransaction(async (transaction) => {
87+
const doc = await transaction.get(rateLimitRef);
88+
const now = Date.now();
89+
const cutoff = now - HEARTBEAT_RATE_LIMIT_MS;
90+
91+
if (doc.exists) {
92+
const lastCall = doc.data()?.['lastCall'];
93+
if (lastCall > cutoff) {
11794
throw new functions.https.HttpsError(
118-
'internal',
119-
'An error occurred during validation or storage'
95+
'resource-exhausted',
96+
'Rate limit exceeded for this public key',
12097
);
98+
}
12199
}
122-
});
100+
101+
transaction.set(rateLimitRef, { lastCall: now }, { merge: true });
102+
});
103+
104+
if (!validateSignature(inputData, signature, publicKey)) {
105+
throw new functions.https.HttpsError(
106+
'unauthenticated',
107+
'Signature validation failed',
108+
);
109+
}
110+
111+
await admin.firestore().collection('heartbeat').add(data);
112+
113+
return { message: 'Data validated and stored successfully' };
114+
} catch (error) {
115+
console.error('Error during data validation and storage:', error);
116+
if (error instanceof functions.https.HttpsError) {
117+
throw error;
118+
}
119+
throw new functions.https.HttpsError(
120+
'internal',
121+
'An error occurred during validation or storage',
122+
);
123+
}
124+
},
125+
);
123126

124127
export { validateSignature };

0 commit comments

Comments
 (0)