submissions: rate limit submit #98

Merged
Quaternions merged 2 commits from pr into staging 2025-04-05 03:23:06 +00:00
4 changed files with 49 additions and 0 deletions

View File

@@ -45,6 +45,7 @@ type Operations interface {
Create(ctx context.Context, smap model.Operation) (model.Operation, error)
Update(ctx context.Context, id int32, values OptionalMap) error
Delete(ctx context.Context, id int32) error
CountSince(ctx context.Context, owner int64, since int64) (int64, error)
}
type Submissions interface {

View File

@@ -53,3 +53,12 @@ func (env *Operations) Delete(ctx context.Context, id int32) error {
return nil
}
func (env *Operations) CountSince(ctx context.Context, owner int64, since int64) (int64, error) {
var count int64
if err := env.db.Where("owner = ? AND created_at > ?",owner,since).Count(&count).Error; err != nil {
return count, err
}
return count, nil
}

View File

@@ -27,12 +27,16 @@ var(
model.MapfixStatusValidating,
model.MapfixStatusAccepted,
}
// Allow 5 mapfixes every 10 minutes
CreateMapfixRateLimit int64 = 5
CreateMapfixRecencyWindow = time.Second*600
)
var (
ErrCreationPhaseMapfixesLimit = errors.New("Active mapfixes limited to 20")
ErrActiveMapfixSameTargetAssetID = errors.New("There is an active mapfix with the same TargetAssetID")
ErrAcceptOwnMapfix = fmt.Errorf("%w: You cannot accept your own mapfix as the submitter", ErrPermissionDenied)
ErrCreateMapfixRateLimit = errors.New("You must not create more than 5 mapfixes every 10 minutes")
)
// POST /mapfixes
@@ -76,6 +80,21 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixTrigger
}
}
// Check if too many operations have been created recently
{
count, err := svc.DB.Operations().CountSince(ctx,
int64(userId),
time.Now().Add(-CreateMapfixRecencyWindow).Unix(),
)
if err != nil {
return nil, err
}
if CreateMapfixRateLimit < count {
return nil, ErrCreateMapfixRateLimit
}
}
operation, err := svc.DB.Operations().Create(ctx, model.Operation{
Owner: int64(userId),
StatusID: model.OperationStatusCreated,

View File

@@ -27,6 +27,9 @@ var(
model.SubmissionStatusValidating,
model.SubmissionStatusAcceptedUnvalidated,
}
// Allow 5 submissions every 10 minutes
CreateSubmissionRateLimit int64 = 5
CreateSubmissionRecencyWindow = time.Second*600
)
var (
@@ -35,6 +38,7 @@ var (
ErrReleaseInvalidStatus = errors.New("Only submissions with Uploaded status can be released")
ErrReleaseNoUploadedAssetID = errors.New("Only submissions with a UploadedAssetID can be released")
ErrAcceptOwnSubmission = fmt.Errorf("%w: You cannot accept your own submission as the submitter", ErrPermissionDenied)
ErrCreateSubmissionRateLimit = errors.New("You must not create more than 5 submissions every 10 minutes")
)
// POST /submissions
@@ -66,6 +70,22 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *api.Submissio
return nil, ErrCreationPhaseSubmissionsLimit
}
}
// Check if too many operations have been created recently
{
count, err := svc.DB.Operations().CountSince(ctx,
int64(userId),
time.Now().Add(-CreateSubmissionRecencyWindow).Unix(),
)
if err != nil {
return nil, err
}
if CreateSubmissionRateLimit < count {
return nil, ErrCreateSubmissionRateLimit
}
}
operation, err := svc.DB.Operations().Create(ctx, model.Operation{
Owner: int64(userId),
StatusID: model.OperationStatusCreated,