diff --git a/app/lib/package/backend.dart b/app/lib/package/backend.dart index 250becf79f..538192cf03 100644 --- a/app/lib/package/backend.dart +++ b/app/lib/package/backend.dart @@ -20,6 +20,7 @@ import 'package:meta/meta.dart'; import 'package:pool/pool.dart'; import 'package:pub_dev/package/export_api_to_bucket.dart'; import 'package:pub_dev/service/async_queue/async_queue.dart'; +import 'package:pub_dev/service/rate_limit/rate_limit.dart'; import 'package:pub_dev/shared/versions.dart'; import 'package:pub_dev/task/backend.dart'; import 'package:pub_package_reader/pub_package_reader.dart'; @@ -1042,6 +1043,13 @@ class PackageBackend { 'Package "${newVersion.package}" has no admin email to notify.'); } + // check rate limits before the transaction + await verifyPackageUploadRateLimit( + agent: agent, + package: newVersion.package, + isNew: isNew, + ); + final email = createPackageUploadedEmail( packageName: newVersion.package, packageVersion: newVersion.version!, diff --git a/app/lib/service/rate_limit/rate_limit.dart b/app/lib/service/rate_limit/rate_limit.dart index 87b9b47bb5..ae1ccd5f8a 100644 --- a/app/lib/service/rate_limit/rate_limit.dart +++ b/app/lib/service/rate_limit/rate_limit.dart @@ -12,6 +12,37 @@ import '../../shared/configuration.dart'; import '../../shared/exceptions.dart'; import '../../shared/redis_cache.dart'; +/// Verifies if the current package upload has a rate limit and throws +/// if the limit has been exceeded. +Future verifyPackageUploadRateLimit({ + required AuthenticatedAgent agent, + required String package, + required bool isNew, +}) async { + final packagePublishedOp = AuditLogRecordKind.packagePublished; + + await _verifyRateLimit( + rateLimit: _getRateLimit(packagePublishedOp, RateLimitScope.user), + agentId: agent.agentId, + ); + + if (isNew) { + await _verifyRateLimit( + rateLimit: _getRateLimit( + AuditLogRecordKind.packageCreated, + RateLimitScope.user, + ), + agentId: agent.agentId, + ); + } + + // regular package-specific limits + await _verifyRateLimit( + rateLimit: _getRateLimit(packagePublishedOp, RateLimitScope.package), + package: package, + ); +} + Future verifyAuditLogRecordRateLimits(AuditLogRecord record) async { final agentId = record.agent; await _verifyRateLimit(