Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / internal/modules/matching/candidate_documents_test.go |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 720d47fae476b0d38477ae4401697d372b1ea2bc |
| Branch | feature/opportunity-to-outcome |
| Path or archive member | internal/modules/matching/candidate_documents_test.go |
| Original SHA-256 | 769f64451a00248829bf879ad125e5249250805ad541778bdc7d54b450957901 |
| Git blob SHA | 582b0a342a4af567af4de9c2f960476491e96e9b |
| Reading-copy SHA-256 | a3fcbb575bc82ff6b4ffc8fb2f67dab22075cf07f15506f9f0a763267c5df366 |
Recovered source transcript
Download complete source text ↓88 lines · 3.7 KB
Credential-bearing and unrelated personal details were removed from this reading copy. The source identity and original checksum remain recorded.
package matching
import (
"strings"
"testing"
)
// The file name is set into a Content-Disposition header and shown to a person. It must never carry a path,
// a quote that would break out of the header, or a control character.
func TestSafeFileName(t *testing.T) {
cases := map[string]string{
"resume.pdf": "resume.pdf",
"../../etc/passwd": "[credential removed]",
"/absolute/path/cv.docx": "cv.docx",
`quote".pdf`: "quote.pdf",
// A backslash is not a path separator on the server's platform, so it is STRIPPED
// rather than split on. The property that matters is that none survives into the
// header, which is asserted below.
`back\slash.pdf`: "backslash.pdf",
"": "document",
" ": "document",
".": "document",
"..": "document",
"C:\\Users\\dana\\resume.pdf": "C:Usersdanaresume.pdf",
}
for in, want := range cases {
if got := safeFileName(in); got != want {
t.Errorf("safeFileName(%q) = %q, want %q", in, got, want)
}
}
// No result may contain anything that would break the header it lands in.
for in := range cases {
got := safeFileName(in)
if strings.ContainsAny(got, "\"\\/\r\n") {
t.Errorf("safeFileName(%q) = %q, which can break a Content-Disposition header", in, got)
}
}
if len(safeFileName(strings.Repeat("a", 500)+".pdf")) > 180 {
t.Error("an absurdly long file name was not bounded")
}
}
// The media type is decided by the SERVER from a closed allowlist. A caller supplied type must never be able
// to introduce something executable.
func TestMediaTypeAllowlist(t *testing.T) {
// The extension wins over the declared type, because a browser's guess is frequently wrong and is always
// caller supplied.
if got := normalizeCandidateMediaType("application/octet-stream", "resume.pdf"); got != "application/pdf" {
t.Errorf("extension should win over a wrong declared type, got %q", got)
}
if got := normalizeCandidateMediaType("text/plain; charset=utf-8", "notes"); got != "text/plain" {
t.Errorf("a parameterised media type should be normalised, got %q", got)
}
// Anything not on the allowlist must be refused. These are the types that make an upload dangerous.
for _, bad := range []string{
"text/html", "application/javascript", "image/svg+xml", "application/x-msdownload",
"application/zip", "", "application/octet-stream",
} {
if _, ok := candidateMediaTypes[bad]; ok {
t.Errorf("%q must not be an accepted media type", bad)
}
}
for _, good := range []string{"application/pdf", "text/plain", "image/png", "image/jpeg"} {
if _, ok := candidateMediaTypes[good]; !ok {
t.Errorf("%q should be accepted", good)
}
}
// An HTML file renamed to .pdf still normalises to pdf and is served with Content-Disposition attachment
// plus nosniff and a sandbox policy, so it cannot execute in the origin. This asserts the first half.
if got := normalizeCandidateMediaType("text/html", "payload.pdf"); got != "application/pdf" {
t.Errorf("a renamed file should take the extension's type, got %q", got)
}
}
// The document type vocabulary must match the migration's CHECK, or a type the handler accepts is refused by
// the database at insert time and surfaces as a 500.
func TestDocumentTypesMatchTheMigration(t *testing.T) {
sql := readFile(t, "../../../db/migrations/0089_candidate_documents_and_messaging.sql")
for typ := range candidateDocTypes {
if !strings.Contains(sql, "'"+typ+"'") {
t.Errorf("document type %q is accepted by the module but is not in the migration's CHECK", typ)
}
}
if !candidateDocTypes["resume"] {
t.Error("resume must be an accepted document type, it is the default")
}
}