Skip to content

Limit script name (50), description (200), and tags (5) to prevent SEO keyword stuffing#1

Draft
Copilot wants to merge 7 commits intomainfrom
copilot/limit-script-name-description-length
Draft

Limit script name (50), description (200), and tags (5) to prevent SEO keyword stuffing#1
Copilot wants to merge 7 commits intomainfrom
copilot/limit-script-name-description-length

Conversation

Copy link
Copy Markdown

Copilot AI commented Apr 12, 2026

Script authors were able to abuse name/description fields with excessive keywords for SEO. Tags had no practical limit. This enforces strict limits so names stay concise, descriptions stay to a single sentence, and additional categorization uses tags (capped at 5).

API binding constraints (library-type scripts)

  • name: max=128max=50
  • description: max=10240/102400max=200
  • tags: max=64max=5

Applies to CreateRequest, UpdateCodeRequest, UpdateSettingRequest, and UpdateLibInfoRequest.

Service-layer validation (userscripts)

For non-library scripts, name/description/tags come from parsed @name/@description/@tags metadata headers in the script code — not from the API request body — so binding constraints alone are insufficient. A validateScriptMeta helper is added and called in both Create and UpdateCode after meta parsing:

// nameInvalidRe rejects SEO keyword-stuffing separators and newlines.
var nameInvalidRe = regexp.MustCompile(`[\r\n,,|;;]`)

// multiSentenceRe detects descriptions that contain more than one sentence.
var multiSentenceRe = regexp.MustCompile(`[\r\n]|[。!?]\s*\S|[.!?]\s+[A-Z\x{4e00}-\x{9fa5}]`)

func validateScriptMeta(ctx context.Context, name, description string, tags []string, nameUnchanged, descUnchanged bool) error {
    if !nameUnchanged {
        if nameInvalidRe.MatchString(name) {
            return i18n.NewError(ctx, code.ScriptNameInvalid)
        }
        if utf8.RuneCountInString(name) > 50 {
            return i18n.NewError(ctx, code.ScriptNameTooLong)
        }
    }
    if !descUnchanged {
        if multiSentenceRe.MatchString(description) {
            return i18n.NewError(ctx, code.ScriptDescInvalid)
        }
        if utf8.RuneCountInString(description) > 200 {
            return i18n.NewError(ctx, code.ScriptDescTooLong)
        }
    }
    if len(tags) > 5 {
        return i18n.NewError(ctx, code.ScriptTagsTooMany)
    }
    return nil
}

Name format check (nameInvalidRe): rejects names containing SEO keyword-list separators — ASCII/Chinese commas (,/), pipes (|), ASCII/Chinese semicolons (;/), and newlines. This prevents patterns like "脚本名称,关键词1,关键词2" or "Script | keyword1 | keyword2".

Description format check (multiSentenceRe): rejects descriptions with more than one sentence:

  • Newlines (\r/\n)
  • Chinese sentence-enders (。!?) followed by optional whitespace then any non-whitespace character — catches both 第一句。第二句 and 第一句。 第二句
  • English sentence-enders (.!?) followed by at least one space then a capital letter or CJK character — catches First. Second without false-positives on v1.0 or URLs

Skip on unchanged: when UpdateCode is called and the parsed name/description matches what is already stored, length and format checks for that field are skipped. This allows existing scripts with values that pre-date these limits to continue being updated without forcing a rename.

Note: system-generated tags (后台脚本, 定时脚本) are appended after validation and do not count toward the user's 5-tag limit.

New error codes

ScriptNameTooLong, ScriptDescTooLong, ScriptTagsTooMany, ScriptNameInvalid, ScriptDescInvalid added to internal/pkg/code/ with Chinese messages describing the new rules.

Unit tests

26 test cases in internal/service/script_svc/script_validate_test.go covering all validation paths — including SEO separator rejection, Chinese/English multi-sentence detection, whitespace-separated sentence detection, length limits, skip-on-unchanged, and tag count — each asserting the specific *httputils.Error code returned.

Original prompt

限制提交的脚本名称和描述的长度,要求脚本名是简单的名称,描述是一段话,避免脚本作者用来塞很多关键字做seo,多的可以用tag来描述,限制5个tag

Copilot AI changed the title [WIP] Add restrictions on script name and description length Limit script name (50), description (200), and tags (5) to prevent SEO keyword stuffing Apr 12, 2026
Copilot AI requested a review from CodFrm April 12, 2026 02:48
@CodFrm
Copy link
Copy Markdown
Member

CodFrm commented Apr 12, 2026

如果是更新,name和description没有变的话,可以跳过,加上检查name是不是简单name,也禁止掉复杂的name,检查description是不是一句话,禁止复杂的描述

Copy link
Copy Markdown
Member

@CodFrm CodFrm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果是更新,name和description没有变的话,可以跳过,加上检查name是不是简单name,也禁止掉复杂的name,检查description是不是一句话,禁止复杂的描述,加上单元测试

Copy link
Copy Markdown
Author

Copilot AI commented Apr 12, 2026

如果是更新,name和description没有变的话,可以跳过,加上检查name是不是简单name,也禁止掉复杂的name,检查description是不是一句话,禁止复杂的描述,加...

Done in commit db1ec35:

  • Skip validation on update when unchanged: UpdateCode now captures oldName/oldDescription before overwriting from parsed metadata, and passes nameUnchanged/descUnchanged flags to validateScriptMeta — if a value hasn't changed, its length/format checks are skipped (allows existing scripts with pre-limit values to be updated without forcing a rename).

  • Simple name check: rejects names containing \r or \n (ScriptNameInvalid).

  • Single-sentence description check: rejects descriptions containing \r or \n (ScriptDescInvalid).

  • Unit tests: 14 test cases in internal/service/script_svc/script_validate_test.go, each asserting the specific *httputils.Error code returned.

如果是更新,name和description没有变的话,可以跳过,加上检查name是不是简单name,也禁止掉复杂的name,检查description是不是一句话,禁止复杂的描述

Done in commit db1ec35 — same changes as above.

Copilot AI requested a review from CodFrm April 12, 2026 03:07
// pre-date these limits can still be updated without forcing the author to rename them.
func validateScriptMeta(ctx context.Context, name, description string, tags []string, nameUnchanged, descUnchanged bool) error {
if !nameUnchanged {
if strings.ContainsAny(name, "\r\n") {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

只是判断换行符太简单了,而且本来也就不允许换行,有没有库可以判断?需要支持i18n,描述也要如此。或者名字禁止标点符号之类,描述判断是不是一句话

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in commit 5e02e37 with two compiled regex patterns (no extra dependencies needed, standard regexp package):

nameInvalidRe — rejects SEO keyword-list separators in names: commas (,/), pipes (|), semicolons (;/), and newlines. Pattern: [\r\n,,|;;]

multiSentenceRe — rejects descriptions with more than one sentence:

  • Newlines ([\r\n])
  • Chinese sentence-enders ([。!?]) followed by optional whitespace then any non-whitespace (covers both 第一句。第二句 and 第一句。 第二句)
  • English sentence-enders ([.!?]) followed by at least one space then a capital letter or CJK character (catches First. Second without false-positives on v1.0 or URLs)

Pattern: [\r\n]|[。!?]\s*\S|[.!?]\s+[A-Z\x{4e00}-\x{9fa5}]

26 unit test cases covering all paths, each asserting the specific *httputils.Error code.

Copilot AI requested a review from CodFrm April 12, 2026 03:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants