From c21ceacd4b1027a68d06931625916ddcb15c79bd Mon Sep 17 00:00:00 2001 From: Max Freedom Pollard <272618364+MaxFreedomPollard@users.noreply.github.com> Date: Sun, 6 Sep 2026 07:05:20 -0400 Subject: [PATCH] fix(libreoffice): report an encrypted .xlsb as password-protected (#1655) Uploading a password-protected .xlsb workbook without its password answered 500 with the unattributable-failure message instead of 400 with the remedy. DetectPasswordProtection in pkg/modules/libreoffice/api/protection.go infers encryption from a compound-file header carried by an extension whose unencrypted form is always a ZIP package. The ooxmlExtensions map listed .xlsx, .xlsm, .xltx and .xltm but not .xlsb, so an encrypted workbook under that extension fell through to PasswordProtectionUnknown. The convert route in pkg/modules/libreoffice/routes.go then matched neither password branch of its exit-code switch and returned the 500 default. An Excel Binary Workbook is an Open Packaging Conventions ZIP holding binary parts, so a compound file under that extension is encrypted for the same reason .xlsx is. Adding .xlsb to the map restores the 400 that names the 'password' form field. --- pkg/modules/libreoffice/api/protection.go | 9 +++++---- pkg/modules/libreoffice/api/protection_test.go | 5 +++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/pkg/modules/libreoffice/api/protection.go b/pkg/modules/libreoffice/api/protection.go index 9ada1596..d9c550cc 100644 --- a/pkg/modules/libreoffice/api/protection.go +++ b/pkg/modules/libreoffice/api/protection.go @@ -35,12 +35,13 @@ var ( zipMagic = []byte{0x50, 0x4b, 0x03, 0x04} // An unencrypted OOXML document is always a ZIP package, so any of these - // extensions over a compound file means the payload is encrypted. Legacy - // binary formats (.doc, .xls, .ppt) are compound files either way and are - // deliberately absent. + // extensions over a compound file means the payload is encrypted. A .xlsb + // workbook stores binary parts inside that same ZIP package, so it belongs + // here too. Legacy binary formats (.doc, .xls, .ppt) are compound files + // either way and are deliberately absent. ooxmlExtensions = map[string]struct{}{ ".docx": {}, ".docm": {}, ".dotx": {}, ".dotm": {}, - ".xlsx": {}, ".xlsm": {}, ".xltx": {}, ".xltm": {}, + ".xlsx": {}, ".xlsm": {}, ".xltx": {}, ".xltm": {}, ".xlsb": {}, ".pptx": {}, ".pptm": {}, ".potx": {}, ".potm": {}, ".ppsx": {}, ".ppsm": {}, } diff --git a/pkg/modules/libreoffice/api/protection_test.go b/pkg/modules/libreoffice/api/protection_test.go index 88fa88df..d71f24ce 100644 --- a/pkg/modules/libreoffice/api/protection_test.go +++ b/pkg/modules/libreoffice/api/protection_test.go @@ -76,6 +76,11 @@ func TestDetectPasswordProtection(t *testing.T) { path: ole2("encrypted.xlsx"), want: PasswordProtectionRequired, }, + { + name: "encrypted binary workbook", + path: ole2("encrypted.xlsb"), + want: PasswordProtectionRequired, + }, { name: "legacy binary document is inconclusive", path: ole2("legacy.doc"),