@@ -23,8 +23,9 @@ const minaClient = new Client({ network: 'testnet' });
23
23
24
24
admin . initializeApp ( ) ;
25
25
26
- // Rate limit duration between heartbeats from the same submitter (15 seconds)
27
- const HEARTBEAT_RATE_LIMIT_MS = 15000 ;
26
+ // Rate limit configuration: sliding window
27
+ const WINDOW_SIZE_MS = 60000 ; // 1 minute window
28
+ const MAX_REQUESTS_PER_WINDOW = 6 ;
28
29
29
30
function validateSignature (
30
31
data : string ,
@@ -96,21 +97,36 @@ export const handleValidationAndStore = onCall(
96
97
const newHeartbeatRef = db . collection ( 'heartbeats' ) . doc ( ) ;
97
98
98
99
await db . runTransaction ( async ( transaction ) => {
99
- const doc = await transaction . get ( rateLimitRef ) ;
100
+ const rateLimitDoc = await transaction . get ( rateLimitRef ) ;
100
101
const now = Date . now ( ) ;
101
- const cutoff = now - HEARTBEAT_RATE_LIMIT_MS ;
102
+ const windowStart = now - WINDOW_SIZE_MS ;
102
103
103
- if ( doc . exists ) {
104
- const lastCall = doc . data ( ) ?. [ 'lastCall' ] ;
105
- if ( lastCall > cutoff ) {
104
+ if ( rateLimitDoc . exists ) {
105
+ const data = rateLimitDoc . data ( ) ;
106
+ const previousTimestamps : number [ ] = data ?. timestamps || [ ] ;
107
+ const currentWindowTimestamps = previousTimestamps . filter ( ts => ts > windowStart ) ;
108
+
109
+ currentWindowTimestamps . push ( now ) ;
110
+
111
+ if ( currentWindowTimestamps . length > MAX_REQUESTS_PER_WINDOW ) {
106
112
throw new functions . https . HttpsError (
107
113
'resource-exhausted' ,
108
- 'Rate limit exceeded for this public key ' ,
114
+ 'Rate limit exceeded' ,
109
115
) ;
110
116
}
117
+
118
+ transaction . set ( rateLimitRef , {
119
+ timestamps : currentWindowTimestamps ,
120
+ lastCall : FieldValue . serverTimestamp ( ) ,
121
+ } ) ;
122
+ } else {
123
+ // First request for this public key
124
+ transaction . set ( rateLimitRef , {
125
+ timestamps : [ now ] ,
126
+ lastCall : FieldValue . serverTimestamp ( ) ,
127
+ } ) ;
111
128
}
112
129
113
- transaction . set ( rateLimitRef , { lastCall : FieldValue . serverTimestamp ( ) } , { merge : true } ) ;
114
130
transaction . create ( newHeartbeatRef , {
115
131
...data ,
116
132
createTime : FieldValue . serverTimestamp ( ) ,
0 commit comments