@@ -6,12 +6,13 @@ use std::time::Duration;
6
6
7
7
use crate :: schema:: { publish_limit_buckets, publish_rate_overrides} ;
8
8
use crate :: sql:: { date_part, floor, greatest, interval_part, least} ;
9
- use crate :: util:: errors:: { AppResult , TooManyRequests } ;
9
+ use crate :: util:: errors:: { cargo_err , AppResult , TooManyRequests } ;
10
10
11
11
#[ derive( Debug , Clone , Copy ) ]
12
12
pub struct PublishRateLimit {
13
13
pub rate : Duration ,
14
14
pub burst : i32 ,
15
+ pub daily : Option < i64 > ,
15
16
}
16
17
17
18
impl Default for PublishRateLimit {
@@ -26,9 +27,14 @@ impl Default for PublishRateLimit {
26
27
. parse ( )
27
28
. ok ( )
28
29
. unwrap_or ( 5 ) ;
30
+ let daily = dotenv:: var ( "MAX_NEW_VERSIONS_DAILY" )
31
+ . unwrap_or_default ( )
32
+ . parse ( )
33
+ . ok ( ) ;
29
34
Self {
30
35
rate : Duration :: from_secs ( 60 ) * minutes,
31
36
burst,
37
+ daily,
32
38
}
33
39
}
34
40
}
@@ -106,6 +112,27 @@ impl PublishRateLimit {
106
112
use diesel:: dsl:: * ;
107
113
( self . rate . as_millis ( ) as i64 ) . milliseconds ( )
108
114
}
115
+
116
+ pub fn check_daily_limit ( & self , krate_id : i32 , conn : & PgConnection ) -> AppResult < ( ) > {
117
+ use crate :: schema:: versions:: dsl:: * ;
118
+ use diesel:: dsl:: { count_star, now, IntervalDsl } ;
119
+
120
+ if let Some ( daily_limit) = self . daily {
121
+ let today: i64 = versions
122
+ . filter ( crate_id. eq ( krate_id) )
123
+ . filter ( created_at. gt ( now - 24 . hours ( ) ) )
124
+ . select ( count_star ( ) )
125
+ . first ( conn)
126
+ . optional ( ) ?
127
+ . unwrap_or_default ( ) ;
128
+ if today >= daily_limit {
129
+ return Err ( cargo_err (
130
+ "You have published too many versions of this crate in the last 24 hours" ,
131
+ ) ) ;
132
+ }
133
+ }
134
+ Ok ( ( ) )
135
+ }
109
136
}
110
137
111
138
#[ cfg( test) ]
@@ -122,6 +149,7 @@ mod tests {
122
149
let rate = PublishRateLimit {
123
150
rate : Duration :: from_secs ( 1 ) ,
124
151
burst : 10 ,
152
+ daily : None ,
125
153
} ;
126
154
let bucket = rate. take_token ( new_user ( & conn, "user1" ) ?, now, & conn) ?;
127
155
let expected = Bucket {
@@ -134,6 +162,7 @@ mod tests {
134
162
let rate = PublishRateLimit {
135
163
rate : Duration :: from_millis ( 50 ) ,
136
164
burst : 20 ,
165
+ daily : None ,
137
166
} ;
138
167
let bucket = rate. take_token ( new_user ( & conn, "user2" ) ?, now, & conn) ?;
139
168
let expected = Bucket {
@@ -153,6 +182,7 @@ mod tests {
153
182
let rate = PublishRateLimit {
154
183
rate : Duration :: from_secs ( 1 ) ,
155
184
burst : 10 ,
185
+ daily : None ,
156
186
} ;
157
187
let user_id = new_user_bucket ( & conn, 5 , now) ?. user_id ;
158
188
let bucket = rate. take_token ( user_id, now, & conn) ?;
@@ -173,6 +203,7 @@ mod tests {
173
203
let rate = PublishRateLimit {
174
204
rate : Duration :: from_secs ( 1 ) ,
175
205
burst : 10 ,
206
+ daily : None ,
176
207
} ;
177
208
let user_id = new_user_bucket ( & conn, 5 , now) ?. user_id ;
178
209
let refill_time = now + chrono:: Duration :: seconds ( 2 ) ;
@@ -198,6 +229,7 @@ mod tests {
198
229
let rate = PublishRateLimit {
199
230
rate : Duration :: from_millis ( 100 ) ,
200
231
burst : 10 ,
232
+ daily : None ,
201
233
} ;
202
234
let user_id = new_user_bucket ( & conn, 5 , now) ?. user_id ;
203
235
let refill_time = now + chrono:: Duration :: milliseconds ( 300 ) ;
@@ -219,6 +251,7 @@ mod tests {
219
251
let rate = PublishRateLimit {
220
252
rate : Duration :: from_millis ( 100 ) ,
221
253
burst : 10 ,
254
+ daily : None ,
222
255
} ;
223
256
let user_id = new_user_bucket ( & conn, 5 , now) ?. user_id ;
224
257
let bucket = rate. take_token ( user_id, now + chrono:: Duration :: milliseconds ( 250 ) , & conn) ?;
@@ -240,6 +273,7 @@ mod tests {
240
273
let rate = PublishRateLimit {
241
274
rate : Duration :: from_secs ( 1 ) ,
242
275
burst : 10 ,
276
+ daily : None ,
243
277
} ;
244
278
let user_id = new_user_bucket ( & conn, 1 , now) ?. user_id ;
245
279
let bucket = rate. take_token ( user_id, now, & conn) ?;
@@ -263,6 +297,7 @@ mod tests {
263
297
let rate = PublishRateLimit {
264
298
rate : Duration :: from_secs ( 1 ) ,
265
299
burst : 10 ,
300
+ daily : None ,
266
301
} ;
267
302
let user_id = new_user_bucket ( & conn, 0 , now) ?. user_id ;
268
303
let refill_time = now + chrono:: Duration :: seconds ( 1 ) ;
@@ -285,6 +320,7 @@ mod tests {
285
320
let rate = PublishRateLimit {
286
321
rate : Duration :: from_secs ( 1 ) ,
287
322
burst : 10 ,
323
+ daily : None ,
288
324
} ;
289
325
let user_id = new_user_bucket ( & conn, 8 , now) ?. user_id ;
290
326
let refill_time = now + chrono:: Duration :: seconds ( 4 ) ;
@@ -307,6 +343,7 @@ mod tests {
307
343
let rate = PublishRateLimit {
308
344
rate : Duration :: from_secs ( 1 ) ,
309
345
burst : 10 ,
346
+ daily : None ,
310
347
} ;
311
348
let user_id = new_user ( & conn, "user1" ) ?;
312
349
let other_user_id = new_user ( & conn, "user2" ) ?;
@@ -334,6 +371,7 @@ mod tests {
334
371
let rate = PublishRateLimit {
335
372
rate : Duration :: from_secs ( 1 ) ,
336
373
burst : 10 ,
374
+ daily : None ,
337
375
} ;
338
376
let user_id = new_user ( & conn, "user1" ) ?;
339
377
let other_user_id = new_user ( & conn, "user2" ) ?;
0 commit comments