tdf#105844 package: remove root document from manifest ...
... for ODF wholesome encryption. 4.3 <manifest:file-entry> For directories, the manifest file should contain a <manifest:file-entry> element only if a directory contains a document or a sub document. Because the "encrypted-package" is not a document but a package, we should probably omit the file-entry for the root document. ZipPackage::writeTempFile() always generates the root document becuase it's needed for GPG properties, and ManifestExport filters it out. A bit tricky to implement, because there isn't a clean distinction between the package and the root document/storage in the package module, in particular there's no other place than the root storage to store the MediaType property. Change-Id: Id7e72a64e2faa074dce80cd5fefb2fa189e2e3ee Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160717 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
This commit is contained in:
@@ -81,6 +81,7 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
|
||||
// find the mediatype of the document if any
|
||||
OUString aDocMediaType;
|
||||
OUString aDocVersion;
|
||||
bool isWholesomeEncryption(false);
|
||||
const uno::Sequence<beans::PropertyValue>* pRootFolderPropSeq = nullptr;
|
||||
for (const uno::Sequence < beans::PropertyValue >& rSequence : rManList)
|
||||
{
|
||||
@@ -109,12 +110,27 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
|
||||
|
||||
if ( aPath == "/" )
|
||||
{
|
||||
assert(aDocMediaType.isEmpty());
|
||||
// unfortunately no aMediaType in some cases where non-documents
|
||||
// are stored as StorageFormats::PACKAGE instead of sensible
|
||||
// StorageFormats::ZIP, such as SvxXMLXTableExportComponent and
|
||||
// SwXMLTextBlocks, which results in an empty "mimetype" etc but
|
||||
// can't be easily fixed; try to exclude these cases by checking
|
||||
// for aVersion, but of course then forgetting to set both version
|
||||
// and type on an actual document can't be found :(
|
||||
assert(!aMediaType.isEmpty() || aVersion.isEmpty());
|
||||
aDocMediaType = aMediaType;
|
||||
aDocVersion = aVersion;
|
||||
pRootFolderPropSeq = &rSequence;
|
||||
break;
|
||||
}
|
||||
|
||||
if (aPath == "encrypted-package")
|
||||
{
|
||||
isWholesomeEncryption = true;
|
||||
assert(aDocMediaType.isEmpty() || aDocMediaType == aMediaType);
|
||||
}
|
||||
}
|
||||
assert(pRootFolderPropSeq);
|
||||
|
||||
bool bProvideDTD = false;
|
||||
bool bAcceptNonemptyVersion = false;
|
||||
@@ -293,7 +309,12 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
|
||||
// now write individual file entries
|
||||
for (const uno::Sequence<beans::PropertyValue>& rSequence : rManList)
|
||||
{
|
||||
if (&rSequence == pRootFolderPropSeq && isWholesomeEncryption)
|
||||
{
|
||||
continue; // no root document, but embedded package => omit
|
||||
}
|
||||
rtl::Reference<::comphelper::AttributeList> pAttrList = new ::comphelper::AttributeList;
|
||||
OUString fullPath;
|
||||
OUString aString;
|
||||
const uno::Any *pVector = nullptr, *pSalt = nullptr, *pIterationCount = nullptr, *pDigest = nullptr, *pDigestAlg = nullptr, *pEncryptAlg = nullptr, *pStartKeyAlg = nullptr, *pDerivedKeySize = nullptr;
|
||||
for (const beans::PropertyValue& rValue : rSequence)
|
||||
@@ -312,8 +333,8 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
|
||||
}
|
||||
else if (rValue.Name == sFullPathProperty )
|
||||
{
|
||||
rValue.Value >>= aString;
|
||||
pAttrList->AddAttribute ( ATTRIBUTE_FULL_PATH, aString );
|
||||
rValue.Value >>= fullPath;
|
||||
pAttrList->AddAttribute(ATTRIBUTE_FULL_PATH, fullPath);
|
||||
}
|
||||
else if (rValue.Name == sSizeProperty )
|
||||
{
|
||||
@@ -338,6 +359,11 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
|
||||
else if (rValue.Name == sDerivedKeySizeProperty )
|
||||
pDerivedKeySize = &rValue.Value;
|
||||
}
|
||||
assert(!fullPath.isEmpty());
|
||||
if (isWholesomeEncryption)
|
||||
{ // there may be signatures in META-INF too
|
||||
assert(fullPath == "encrypted-package" || fullPath.startsWith("META-INF/"));
|
||||
}
|
||||
|
||||
xHandler->ignorableWhitespace ( sWhiteSpace );
|
||||
xHandler->startElement( ELEMENT_FILE_ENTRY , pAttrList);
|
||||
@@ -390,6 +416,7 @@ ManifestExport::ManifestExport( uno::Reference< xml::sax::XDocumentHandler > con
|
||||
}
|
||||
else if (nEncAlgID == xml::crypto::CipherID::AES_GCM_W3C)
|
||||
{
|
||||
assert(bStoreStartKeyGeneration || pKeyInfoProperty);
|
||||
SAL_WARN_IF(nDerivedKeySize != 32, "package.manifest", "Unexpected key size is provided!");
|
||||
if (nDerivedKeySize != 32)
|
||||
{
|
||||
|
||||
@@ -647,7 +647,8 @@ uno::Reference< XInputStream > ZipFile::createStreamForZipEntry(
|
||||
#ifndef EMSCRIPTEN
|
||||
static const sal_Int32 nThreadingThreshold = 10000;
|
||||
|
||||
if( xSrcStream->available() > nThreadingThreshold )
|
||||
// "encrypted-package" is the only data stream, no point in threading it
|
||||
if (rEntry.sPath != "encrypted-package" && nThreadingThreshold < xSrcStream->available())
|
||||
xBufStream = new XBufferedThreadedStream(xSrcStream, xSrcStream->getSize());
|
||||
else
|
||||
#endif
|
||||
|
||||
@@ -417,25 +417,36 @@ void ZipPackage::parseManifest()
|
||||
}
|
||||
}
|
||||
|
||||
if ( !bManifestParsed )
|
||||
if (!bManifestParsed || m_xRootFolder->GetMediaType().isEmpty())
|
||||
{
|
||||
// the manifest.xml could not be successfully parsed, this is an inconsistent package
|
||||
if ( aPackageMediatype.startsWith("application/vnd.") )
|
||||
{
|
||||
// accept only types that look similar to own mediatypes
|
||||
m_xRootFolder->SetMediaType( aPackageMediatype );
|
||||
m_bMediaTypeFallbackUsed = true;
|
||||
// if there is an encrypted inner package, there is no root
|
||||
// document, because instead there is a package, and it is not
|
||||
// an error
|
||||
if (!m_xRootFolder->hasByName("encrypted-package"))
|
||||
{
|
||||
m_bMediaTypeFallbackUsed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( !m_bForceRecovery )
|
||||
{
|
||||
// the mimetype stream should contain the information from manifest.xml
|
||||
if ( m_xRootFolder->GetMediaType() != aPackageMediatype )
|
||||
// the mimetype stream should contain the same information as manifest.xml
|
||||
OUString const mediaTypeXML(m_xRootFolder->hasByName("encrypted-package")
|
||||
? m_xRootFolder->doGetByName("encrypted-package").xPackageEntry->GetMediaType()
|
||||
: m_xRootFolder->GetMediaType());
|
||||
if (mediaTypeXML != aPackageMediatype)
|
||||
{
|
||||
throw ZipIOException(
|
||||
THROW_WHERE
|
||||
"mimetype conflicts with manifest.xml, \""
|
||||
+ m_xRootFolder->GetMediaType() + "\" vs. \""
|
||||
+ mediaTypeXML + "\" vs. \""
|
||||
+ aPackageMediatype + "\"" );
|
||||
}
|
||||
}
|
||||
|
||||
m_xRootFolder->removeByName( sMimetype );
|
||||
@@ -1269,6 +1280,8 @@ uno::Reference< io::XInputStream > ZipPackage::writeTempFile()
|
||||
static constexpr OUStringLiteral sFullPath(u"FullPath");
|
||||
const bool bIsGpgEncrypt = m_aGpgProps.hasElements();
|
||||
|
||||
// note: this is always created here (needed for GPG), possibly
|
||||
// filtered out later in ManifestExport
|
||||
if ( m_nFormat == embed::StorageFormats::PACKAGE )
|
||||
{
|
||||
uno::Sequence < PropertyValue > aPropSeq(
|
||||
|
||||
@@ -227,7 +227,13 @@ bool SvxXMLXTableExportComponent::save(
|
||||
if( !bToStorage || !xStorage.is() )
|
||||
{ // local URL -> SfxMedium route
|
||||
if( bSaveAsStorage )
|
||||
{
|
||||
// ideally this should use a ZIP_STORAGE_FORMAT_STRING storage
|
||||
// but changing it to that could cause problems loading the
|
||||
// file with an old version of LO that expects to find in the
|
||||
// user profile a PACKAGE_STORAGE_FORMAT_STRING storage
|
||||
xSubStorage = ::comphelper::OStorageHelper::GetStorageFromURL( rURL, eCreate );
|
||||
}
|
||||
else
|
||||
{
|
||||
pMedium.reset(new SfxMedium( rURL, StreamMode::WRITE | StreamMode::TRUNC ));
|
||||
|
||||
Reference in New Issue
Block a user