diff --git a/internal/core/posts/service.go b/internal/core/posts/service.go index e15652b..1bcb3f7 100644 --- a/internal/core/posts/service.go +++ b/internal/core/posts/service.go @@ -935,6 +935,11 @@ const ( maxTagLength = 640 ) +// MaxContentLength is the post body cap, in BYTES — it matches the postv2 +// lexicon. Create and edit both enforce it through +// normalizeAndValidatePostContent. +const MaxContentLength = 500000 + // normalizeAndValidatePostContent is the definition of a well-formed Coves post, // and it is SHARED by the create and the edit path rather than duplicated across // them. @@ -989,13 +994,12 @@ const ( func normalizeAndValidatePostContent(post postContent) error { // Global content limits (from lexicon) const ( - maxContentLength = 500000 // 500k bytes - matches the postv2 lexicon - maxTitleLength = 3000 // 3k bytes + maxTitleLength = 3000 // 3k bytes ) - if post.Content != nil && len(*post.Content) > maxContentLength { + if post.Content != nil && len(*post.Content) > MaxContentLength { return NewValidationError("content", - fmt.Sprintf("content too long (max %d characters)", maxContentLength)) + fmt.Sprintf("content too long (max %d characters)", MaxContentLength)) } if post.Title != nil && len(*post.Title) > maxTitleLength { diff --git a/internal/core/posts/service_create_validation_test.go b/internal/core/posts/service_create_validation_test.go index c7a9753..8cb0280 100644 --- a/internal/core/posts/service_create_validation_test.go +++ b/internal/core/posts/service_create_validation_test.go @@ -203,9 +203,10 @@ func TestService_CreateResolvesTheCommunityAndValidatesTheRequest(t *testing.T) }) t.Run("Rejects content over the length limit", func(t *testing.T) { - // One byte past maxContentLength (500,000). The limit is what keeps a - // single record from being unbounded on the way to the PDS. - longContent := string(make([]byte, 500001)) + // One byte past the service's own content cap, derived from it so a + // change to the cap cannot leave this fixture behind. The limit is what + // keeps a single record from being unbounded on the way to the PDS. + longContent := string(make([]byte, posts.MaxContentLength+1)) err := createPost(posts.CreatePostRequest{ Community: community.DID, Content: &longContent, diff --git a/internal/core/posts/service_update_validation_test.go b/internal/core/posts/service_update_validation_test.go index 44bcb9a..06f0f6f 100644 --- a/internal/core/posts/service_update_validation_test.go +++ b/internal/core/posts/service_update_validation_test.go @@ -125,7 +125,7 @@ func TestService_UpdateRefusesContentCreateWouldHaveRefused(t *testing.T) { }, { name: "content past the lexicon's cap", - req: posts.UpdatePostRequest{Content: ptr(strings.Repeat("b", 500001))}, + req: posts.UpdatePostRequest{Content: ptr(strings.Repeat("b", posts.MaxContentLength+1))}, }, { name: "a label outside the allowlist",