From 041e977dfc5c84ef5b38199c9b91c1586c59df90 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Fri, 23 Jan 2026 21:32:49 +0100 Subject: macos: normalize unicode file names in forward mode Summary: Store as NFC, read as NFD. This commit resolves https://github.com/rfjakob/gocryptfs/issues/850 by addressing Unicode normalization mismatches on macOS between NFC (used by CLI tools) and NFD (used by GUI apps). The solution is inspired by Cryptomator's approach ( https://github.com/cryptomator/cryptomator/issues/264 ). Forward mode on MacOS now enforces NFC for storage but presents NFD as recommended by https://developer.apple.com/library/archive/qa/qa1173/_index.html and https://github.com/macfuse/macfuse/wiki/File-Names-(Unicode-Normalization-Forms) . See https://github.com/rfjakob/gocryptfs/pull/949 for more info. This commit does nothing for reverse mode as it is not clear if anything can be done. Reverse mode can not influence how the file names are stored, hence mapping normalized names back to what is actually on disk seems difficult. --- internal/nametransform/nfc_test.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 internal/nametransform/nfc_test.go (limited to 'internal/nametransform/nfc_test.go') diff --git a/internal/nametransform/nfc_test.go b/internal/nametransform/nfc_test.go new file mode 100644 index 0000000..aad1d7d --- /dev/null +++ b/internal/nametransform/nfc_test.go @@ -0,0 +1,29 @@ +package nametransform + +import ( + "strconv" + "testing" + + "golang.org/x/text/unicode/norm" +) + +func TestNFD2NFC(t *testing.T) { + n := newLognamesTestInstance(NameMax) + n.nfd2nfc = true + iv := make([]byte, DirIVLen) + srcNFC := "Österreich Café" + srcNFD := norm.NFD.String(srcNFC) + + // cipherName should get normalized to NFC + cipherName, _ := n.EncryptName(srcNFD, iv) + // Decrypt without changing normalization + decryptedRaw, _ := n.decryptName(cipherName, iv) + if srcNFC != decryptedRaw { + t.Errorf("want %s have %s", strconv.QuoteToASCII(srcNFC), strconv.QuoteToASCII(decryptedRaw)) + } + // Decrypt with normalizing to NFD + decrypted, _ := n.DecryptName(cipherName, iv) + if srcNFD != decrypted { + t.Errorf("want %s have %s", strconv.QuoteToASCII(srcNFD), strconv.QuoteToASCII(decrypted)) + } +} -- cgit v1.2.3