diff --git a/cmd/fscrypt/flags.go b/cmd/fscrypt/flags.go index 3d3c51d5..022deb75 100644 --- a/cmd/fscrypt/flags.go +++ b/cmd/fscrypt/flags.go @@ -257,8 +257,10 @@ var ( ) // The first group is optional and corresponds to the mountpoint. The second -// group is required and corresponds to the descriptor. -var idFlagRegex = regexp.MustCompile("^([[:print:]]+):([[:alnum:]]+)$") +// group is required and corresponds to the descriptor. The mountpoint may +// contain any non-control Unicode character (e.g. accented letters in paths), +// so we use [^\p{Cc}] rather than the ASCII-only [[:print:]]. +var idFlagRegex = regexp.MustCompile(`^([^\p{Cc}]+):([[:alnum:]]+)$`) func matchMetadataFlag(flagValue string) (mountpoint, descriptor string, err error) { matches := idFlagRegex.FindStringSubmatch(flagValue) diff --git a/cmd/fscrypt/fscrypt_test.go b/cmd/fscrypt/fscrypt_test.go index 1d09bf8d..5148cb7b 100644 --- a/cmd/fscrypt/fscrypt_test.go +++ b/cmd/fscrypt/fscrypt_test.go @@ -19,6 +19,71 @@ package main -import "testing" +import ( + "strings" + "testing" +) func TestTrivial(t *testing.T) {} + +func TestMatchMetadataFlag(t *testing.T) { + testCases := []struct { + flagValue string + wantMountpoint string + wantDescriptor string + wantErrSubstring string + }{ + { + flagValue: "/mnt/ext4:c198cb2e6ceb4a12", + wantMountpoint: "/mnt/ext4", + wantDescriptor: "c198cb2e6ceb4a12", + }, + { + // The mountpoint may contain non-ASCII characters. + flagValue: "/mnt/miroir-données:d77aa788ff9d1931", + wantMountpoint: "/mnt/miroir-données", + wantDescriptor: "d77aa788ff9d1931", + }, + { + flagValue: "/mnt/naïve:abc123", + wantMountpoint: "/mnt/naïve", + wantDescriptor: "abc123", + }, + { + // Missing separator or descriptor is rejected. + flagValue: "abc", + wantErrSubstring: "does not have format", + }, + { + flagValue: ":abc", + wantErrSubstring: "does not have format", + }, + { + flagValue: "abc:", + wantErrSubstring: "does not have format", + }, + { + // Control characters in the mountpoint are rejected. + flagValue: "/mnt/path\nwithnewline:abc", + wantErrSubstring: "does not have format", + }, + } + for _, tc := range testCases { + mountpoint, descriptor, err := matchMetadataFlag(tc.flagValue) + if tc.wantErrSubstring != "" { + if err == nil || !strings.Contains(err.Error(), tc.wantErrSubstring) { + t.Errorf("matchMetadataFlag(%q) error = %v, want error containing %q", + tc.flagValue, err, tc.wantErrSubstring) + } + continue + } + if err != nil { + t.Errorf("matchMetadataFlag(%q) returned unexpected error: %v", tc.flagValue, err) + continue + } + if mountpoint != tc.wantMountpoint || descriptor != tc.wantDescriptor { + t.Errorf("matchMetadataFlag(%q) = (%q, %q), want (%q, %q)", + tc.flagValue, mountpoint, descriptor, tc.wantMountpoint, tc.wantDescriptor) + } + } +}