diff options
author | 2024-02-14 11:13:38 +0000 | |
---|---|---|
committer | 2024-02-14 12:13:38 +0100 | |
commit | 2bafd7daf542d985ee76d9079a30a602cb7be827 (patch) | |
tree | 8817fe6f202155d660d75c17cd78ff5dae3d4530 /internal/api/util/mime.go | |
parent | [feature] Add metrics for instance user count, statuses count and federating ... (diff) | |
download | gotosocial-2bafd7daf542d985ee76d9079a30a602cb7be827.tar.xz |
[bugfix] add stricter checks during all stages of dereferencing remote AS objects (#2639)
* add stricter checks during all stages of dereferencing remote AS objects
* a comment
Diffstat (limited to 'internal/api/util/mime.go')
-rw-r--r-- | internal/api/util/mime.go | 114 |
1 files changed, 113 insertions, 1 deletions
diff --git a/internal/api/util/mime.go b/internal/api/util/mime.go index ad1b405cd..455a84de9 100644 --- a/internal/api/util/mime.go +++ b/internal/api/util/mime.go @@ -17,6 +17,8 @@ package util +import "strings" + const ( // Possible GoToSocial mimetypes. AppJSON = `application/json` @@ -24,7 +26,8 @@ const ( AppXMLXRD = `application/xrd+xml` AppRSSXML = `application/rss+xml` AppActivityJSON = `application/activity+json` - AppActivityLDJSON = `application/ld+json; profile="https://www.w3.org/ns/activitystreams"` + appActivityLDJSON = `application/ld+json` // without profile + AppActivityLDJSON = appActivityLDJSON + `; profile="https://www.w3.org/ns/activitystreams"` AppJRDJSON = `application/jrd+json` // https://www.rfc-editor.org/rfc/rfc7033#section-10.2 AppForm = `application/x-www-form-urlencoded` MultipartForm = `multipart/form-data` @@ -32,3 +35,112 @@ const ( TextHTML = `text/html` TextCSS = `text/css` ) + +// JSONContentType returns whether is application/json(;charset=utf-8)? content-type. +func JSONContentType(ct string) bool { + p := splitContentType(ct) + p, ok := isUTF8ContentType(p) + return ok && len(p) == 1 && + p[0] == AppJSON +} + +// JSONJRDContentType returns whether is application/(jrd+)?json(;charset=utf-8)? content-type. +func JSONJRDContentType(ct string) bool { + p := splitContentType(ct) + p, ok := isUTF8ContentType(p) + return ok && len(p) == 1 && + p[0] == AppJSON || + p[0] == AppJRDJSON +} + +// XMLContentType returns whether is application/xml(;charset=utf-8)? content-type. +func XMLContentType(ct string) bool { + p := splitContentType(ct) + p, ok := isUTF8ContentType(p) + return ok && len(p) == 1 && + p[0] == AppXML +} + +// XMLXRDContentType returns whether is application/(xrd+)?xml(;charset=utf-8)? content-type. +func XMLXRDContentType(ct string) bool { + p := splitContentType(ct) + p, ok := isUTF8ContentType(p) + return ok && len(p) == 1 && + p[0] == AppXML || + p[0] == AppXMLXRD +} + +// ASContentType returns whether is valid ActivityStreams content-types: +// - application/activity+json +// - application/ld+json;profile=https://w3.org/ns/activitystreams +func ASContentType(ct string) bool { + p := splitContentType(ct) + p, ok := isUTF8ContentType(p) + if !ok { + return false + } + switch len(p) { + case 1: + return p[0] == AppActivityJSON + case 2: + return p[0] == appActivityLDJSON && + p[1] == "profile=https://www.w3.org/ns/activitystreams" || + p[1] == "profile=\"https://www.w3.org/ns/activitystreams\"" + default: + return false + } +} + +// NodeInfo2ContentType returns whether is nodeinfo schema 2.0 content-type. +func NodeInfo2ContentType(ct string) bool { + p := splitContentType(ct) + p, ok := isUTF8ContentType(p) + if !ok { + return false + } + switch len(p) { + case 1: + return p[0] == AppJSON + case 2: + return p[0] == AppJSON && + p[1] == "profile=\"http://nodeinfo.diaspora.software/ns/schema/2.0#\"" || + p[1] == "profile=http://nodeinfo.diaspora.software/ns/schema/2.0#" + default: + return false + } +} + +// isUTF8ContentType checks for a provided charset in given +// type parts list, removes it and returns whether is utf-8. +func isUTF8ContentType(p []string) ([]string, bool) { + const charset = "charset=" + const charsetUTF8 = charset + "utf-8" + for i, part := range p { + + // Only handle charset slice parts. + if part[:len(charset)] == charset { + + // Check if is UTF-8 charset. + ok := (part == charsetUTF8) + + // Drop this slice part. + _ = copy(p[i:], p[i+1:]) + p = p[:len(p)-1] + + return p, ok + } + } + return p, true +} + +// splitContentType splits content-type into semi-colon +// separated parts. useful when a charset is provided. +// note this also maps all chars to their lowercase form. +func splitContentType(ct string) []string { + s := strings.Split(ct, ";") + for i := range s { + s[i] = strings.TrimSpace(s[i]) + s[i] = strings.ToLower(s[i]) + } + return s +} |