/src/libreoffice/comphelper/source/misc/storagehelper.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #include <config_gpgme.h> |
21 | | |
22 | | #include <com/sun/star/embed/ElementModes.hpp> |
23 | | #include <com/sun/star/embed/XEncryptionProtectedStorage.hpp> |
24 | | #include <com/sun/star/embed/XStorage.hpp> |
25 | | #include <com/sun/star/embed/XTransactedObject.hpp> |
26 | | #include <com/sun/star/embed/StorageFactory.hpp> |
27 | | #include <com/sun/star/embed/FileSystemStorageFactory.hpp> |
28 | | #include <com/sun/star/io/IOException.hpp> |
29 | | #include <com/sun/star/lang/XSingleServiceFactory.hpp> |
30 | | #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> |
31 | | #include <com/sun/star/ucb/SimpleFileAccess.hpp> |
32 | | #include <com/sun/star/beans/XPropertySet.hpp> |
33 | | #include <com/sun/star/beans/PropertyValue.hpp> |
34 | | #include <com/sun/star/beans/NamedValue.hpp> |
35 | | #include <com/sun/star/beans/IllegalTypeException.hpp> |
36 | | #include <com/sun/star/security/DocumentDigitalSignatures.hpp> |
37 | | #include <com/sun/star/security/XCertificate.hpp> |
38 | | |
39 | | #include <vector> |
40 | | |
41 | | #include <rtl/digest.h> |
42 | | #include <rtl/random.h> |
43 | | #include <sal/log.hxx> |
44 | | |
45 | | #include <ucbhelper/content.hxx> |
46 | | |
47 | | #include <comphelper/bytereader.hxx> |
48 | | #include <comphelper/diagnose_ex.hxx> |
49 | | #include <comphelper/fileformat.h> |
50 | | #include <comphelper/hash.hxx> |
51 | | #include <comphelper/processfactory.hxx> |
52 | | #include <comphelper/documentconstants.hxx> |
53 | | #include <comphelper/propertyvalue.hxx> |
54 | | #include <comphelper/storagehelper.hxx> |
55 | | #include <comphelper/sequence.hxx> |
56 | | #include <comphelper/xmlsechelper.hxx> |
57 | | #include <cppuhelper/exc_hlp.hxx> |
58 | | #include <o3tl/string_view.hxx> |
59 | | |
60 | | #if HAVE_FEATURE_GPGME |
61 | | # include <context.h> |
62 | | # include <encryptionresult.h> |
63 | | # include <key.h> |
64 | | # include <data.h> |
65 | | #endif |
66 | | |
67 | | using namespace ::com::sun::star; |
68 | | |
69 | | namespace comphelper { |
70 | | |
71 | | |
72 | | uno::Reference< lang::XSingleServiceFactory > OStorageHelper::GetStorageFactory( |
73 | | const uno::Reference< uno::XComponentContext >& rxContext ) |
74 | 263k | { |
75 | 263k | uno::Reference< uno::XComponentContext> xContext = rxContext.is() ? rxContext : ::comphelper::getProcessComponentContext(); |
76 | | |
77 | 263k | return embed::StorageFactory::create( xContext ); |
78 | 263k | } |
79 | | |
80 | | |
81 | | uno::Reference< lang::XSingleServiceFactory > OStorageHelper::GetFileSystemStorageFactory( |
82 | | const uno::Reference< uno::XComponentContext >& rxContext ) |
83 | 0 | { |
84 | 0 | return embed::FileSystemStorageFactory::create(rxContext); |
85 | 0 | } |
86 | | |
87 | | |
88 | | uno::Reference< embed::XStorage > OStorageHelper::GetTemporaryStorage( |
89 | | const uno::Reference< uno::XComponentContext >& rxContext ) |
90 | 203k | { |
91 | 203k | uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( rxContext )->createInstance(), |
92 | 203k | uno::UNO_QUERY_THROW ); |
93 | 203k | return xTempStorage; |
94 | 203k | } |
95 | | |
96 | | |
97 | | uno::Reference< embed::XStorage > OStorageHelper::GetStorageFromURL( |
98 | | const OUString& aURL, |
99 | | sal_Int32 nStorageMode, |
100 | | const uno::Reference< uno::XComponentContext >& rxContext ) |
101 | 0 | { |
102 | 0 | uno::Sequence< uno::Any > aArgs{ uno::Any(aURL), uno::Any(nStorageMode) }; |
103 | 0 | uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( rxContext )->createInstanceWithArguments( aArgs ), |
104 | 0 | uno::UNO_QUERY_THROW ); |
105 | 0 | return xTempStorage; |
106 | 0 | } |
107 | | |
108 | | |
109 | | uno::Reference< embed::XStorage > OStorageHelper::GetStorageFromURL2( |
110 | | const OUString& aURL, |
111 | | sal_Int32 nStorageMode, |
112 | | const uno::Reference< uno::XComponentContext >& rxContext ) |
113 | 0 | { |
114 | 0 | uno::Sequence< uno::Any > aArgs{ uno::Any(aURL), uno::Any(nStorageMode) }; |
115 | |
|
116 | 0 | uno::Reference< lang::XSingleServiceFactory > xFact; |
117 | 0 | css::uno::Any anyEx; |
118 | 0 | try { |
119 | 0 | ::ucbhelper::Content aCntnt( aURL, |
120 | 0 | uno::Reference< css::ucb::XCommandEnvironment > (), |
121 | 0 | getProcessComponentContext() ); |
122 | 0 | if (aCntnt.isDocument()) { |
123 | 0 | xFact = GetStorageFactory( rxContext ); |
124 | 0 | } else { |
125 | 0 | xFact = GetFileSystemStorageFactory( rxContext ); |
126 | 0 | } |
127 | 0 | } catch (uno::Exception &) |
128 | 0 | { |
129 | 0 | anyEx = cppu::getCaughtException(); |
130 | 0 | } |
131 | |
|
132 | 0 | if (!xFact.is()) |
133 | 0 | { |
134 | 0 | if (anyEx.hasValue()) |
135 | 0 | throw css::lang::WrappedTargetRuntimeException( u""_ustr, nullptr, anyEx ); |
136 | 0 | else |
137 | 0 | throw uno::RuntimeException(); |
138 | 0 | } |
139 | | |
140 | 0 | uno::Reference< embed::XStorage > xTempStorage( |
141 | 0 | xFact->createInstanceWithArguments( aArgs ), uno::UNO_QUERY_THROW ); |
142 | 0 | return xTempStorage; |
143 | 0 | } |
144 | | |
145 | | |
146 | | uno::Reference< embed::XStorage > OStorageHelper::GetStorageFromInputStream( |
147 | | const uno::Reference < io::XInputStream >& xStream, |
148 | | const uno::Reference< uno::XComponentContext >& rxContext ) |
149 | 0 | { |
150 | 0 | uno::Sequence< uno::Any > aArgs{ uno::Any(xStream), uno::Any(embed::ElementModes::READ) }; |
151 | 0 | uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( rxContext )->createInstanceWithArguments( aArgs ), |
152 | 0 | uno::UNO_QUERY_THROW ); |
153 | 0 | return xTempStorage; |
154 | 0 | } |
155 | | |
156 | | |
157 | | uno::Reference< embed::XStorage > OStorageHelper::GetStorageFromStream( |
158 | | const uno::Reference < io::XStream >& xStream, |
159 | | sal_Int32 nStorageMode, |
160 | | const uno::Reference< uno::XComponentContext >& rxContext ) |
161 | 0 | { |
162 | 0 | uno::Sequence< uno::Any > aArgs{ uno::Any(xStream), uno::Any(nStorageMode) }; |
163 | 0 | uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( rxContext )->createInstanceWithArguments( aArgs ), |
164 | 0 | uno::UNO_QUERY_THROW ); |
165 | 0 | return xTempStorage; |
166 | 0 | } |
167 | | |
168 | | |
169 | | void OStorageHelper::CopyInputToOutput( |
170 | | const uno::Reference< io::XInputStream >& xInput, |
171 | | const uno::Reference< io::XOutputStream >& xOutput ) |
172 | 15.7k | { |
173 | 15.7k | static const sal_Int32 nConstBufferSize = 32000; |
174 | | |
175 | 15.7k | if (auto pByteReader = dynamic_cast< comphelper::ByteReader* >( xInput.get() )) |
176 | 15.7k | { |
177 | 15.7k | if (auto pByteWriter = dynamic_cast< comphelper::ByteWriter* >( xOutput.get() )) |
178 | 15.7k | { |
179 | 15.7k | sal_Int32 nRead; |
180 | 15.7k | sal_Int8 aTempBuf[ nConstBufferSize ]; |
181 | 15.7k | do |
182 | 16.0k | { |
183 | 16.0k | nRead = pByteReader->readSomeBytes ( aTempBuf, nConstBufferSize ); |
184 | 16.0k | pByteWriter->writeBytes ( aTempBuf, nRead ); |
185 | 16.0k | } |
186 | 16.0k | while ( nRead == nConstBufferSize ); |
187 | 15.7k | return; |
188 | 15.7k | } |
189 | 15.7k | } |
190 | | |
191 | 0 | sal_Int32 nRead; |
192 | 0 | uno::Sequence < sal_Int8 > aSequence ( nConstBufferSize ); |
193 | 0 | do |
194 | 0 | { |
195 | 0 | nRead = xInput->readBytes ( aSequence, nConstBufferSize ); |
196 | 0 | if ( nRead < nConstBufferSize ) |
197 | 0 | aSequence.realloc( nRead ); |
198 | 0 | xOutput->writeBytes ( aSequence ); |
199 | 0 | } |
200 | 0 | while ( nRead == nConstBufferSize ); |
201 | 0 | } |
202 | | |
203 | | |
204 | | uno::Reference< io::XInputStream > OStorageHelper::GetInputStreamFromURL( |
205 | | const OUString& aURL, |
206 | | const uno::Reference< uno::XComponentContext >& context ) |
207 | 0 | { |
208 | 0 | uno::Reference< io::XInputStream > xInputStream = ucb::SimpleFileAccess::create(context)->openFileRead( aURL ); |
209 | 0 | if ( !xInputStream.is() ) |
210 | 0 | throw uno::RuntimeException(); |
211 | | |
212 | 0 | return xInputStream; |
213 | 0 | } |
214 | | |
215 | | |
216 | | void OStorageHelper::SetCommonStorageEncryptionData( |
217 | | const uno::Reference< embed::XStorage >& xStorage, |
218 | | const uno::Sequence< beans::NamedValue >& aEncryptionData ) |
219 | 0 | { |
220 | 0 | uno::Reference< embed::XEncryptionProtectedStorage > xEncrSet( xStorage, uno::UNO_QUERY ); |
221 | 0 | if ( !xEncrSet.is() ) |
222 | 0 | throw io::IOException(u"no XEncryptionProtectedStorage"_ustr); // TODO |
223 | | |
224 | 0 | if ( aEncryptionData.getLength() == 2 && |
225 | 0 | aEncryptionData[0].Name == "GpgInfos" && |
226 | 0 | aEncryptionData[1].Name == "EncryptionKey" ) |
227 | 0 | { |
228 | 0 | xEncrSet->setGpgProperties( |
229 | 0 | aEncryptionData[0].Value.get< uno::Sequence< uno::Sequence< beans::NamedValue > > >() ); |
230 | 0 | xEncrSet->setEncryptionData( |
231 | 0 | aEncryptionData[1].Value.get< uno::Sequence< beans::NamedValue > >() ); |
232 | 0 | } |
233 | 0 | else |
234 | 0 | xEncrSet->setEncryptionData( aEncryptionData ); |
235 | 0 | } |
236 | | |
237 | | |
238 | | sal_Int32 OStorageHelper::GetXStorageFormat( |
239 | | const uno::Reference< embed::XStorage >& xStorage ) |
240 | 125k | { |
241 | 125k | uno::Reference< beans::XPropertySet > xStorProps( xStorage, uno::UNO_QUERY_THROW ); |
242 | | |
243 | 125k | OUString aMediaType; |
244 | 125k | xStorProps->getPropertyValue(u"MediaType"_ustr) >>= aMediaType; |
245 | | |
246 | 125k | sal_Int32 nResult = 0; |
247 | | |
248 | | // TODO/LATER: the filter configuration could be used to detect it later, or better a special service |
249 | 125k | if ( |
250 | 125k | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_WRITER ) || |
251 | 125k | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_WRITER_WEB ) || |
252 | 125k | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_WRITER_GLOBAL) || |
253 | 125k | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_DRAW ) || |
254 | 125k | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_IMPRESS ) || |
255 | 125k | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_CALC ) || |
256 | 125k | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_CHART ) || |
257 | 125k | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_VND_SUN_XML_MATH ) |
258 | 125k | ) |
259 | 0 | { |
260 | 0 | nResult = SOFFICE_FILEFORMAT_60; |
261 | 0 | } |
262 | 125k | else if ( |
263 | 125k | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT ) || |
264 | 95.7k | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB ) || |
265 | 95.7k | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL ) || |
266 | 95.7k | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_DRAWING ) || |
267 | 95.7k | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION) || |
268 | 73.2k | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET ) || |
269 | 27.4k | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_CHART ) || |
270 | 27.4k | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_FORMULA ) || |
271 | 0 | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_DATABASE ) || |
272 | 0 | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_REPORT ) || |
273 | 0 | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_REPORT_CHART) || |
274 | 0 | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE ) || |
275 | 0 | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_TEMPLATE ) || |
276 | 0 | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE ) || |
277 | 0 | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE) || |
278 | 0 | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE ) || |
279 | 0 | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_CHART_TEMPLATE ) || |
280 | 0 | aMediaType.equalsIgnoreAsciiCase(MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE ) |
281 | 125k | ) |
282 | 125k | { |
283 | 125k | nResult = SOFFICE_FILEFORMAT_8; |
284 | 125k | } |
285 | 0 | else |
286 | 0 | { |
287 | | // the mediatype is not known |
288 | 0 | throw beans::IllegalTypeException("unknown media type '" + aMediaType + "'"); |
289 | 0 | } |
290 | | |
291 | 125k | return nResult; |
292 | 125k | } |
293 | | |
294 | | |
295 | | uno::Reference< embed::XStorage > OStorageHelper::GetStorageOfFormatFromURL( |
296 | | const OUString& aFormat, |
297 | | const OUString& aURL, |
298 | | sal_Int32 nStorageMode, |
299 | | const uno::Reference< uno::XComponentContext >& rxContext ) |
300 | 0 | { |
301 | 0 | uno::Sequence< beans::PropertyValue > aProps{ comphelper::makePropertyValue(u"StorageFormat"_ustr, |
302 | 0 | aFormat) }; |
303 | |
|
304 | 0 | uno::Sequence< uno::Any > aArgs{ uno::Any(aURL), uno::Any(nStorageMode), uno::Any(aProps) }; |
305 | 0 | uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( rxContext )->createInstanceWithArguments( aArgs ), |
306 | 0 | uno::UNO_QUERY_THROW ); |
307 | 0 | return xTempStorage; |
308 | 0 | } |
309 | | |
310 | | |
311 | | uno::Reference< embed::XStorage > OStorageHelper::GetStorageOfFormatFromInputStream( |
312 | | const OUString& aFormat, |
313 | | const uno::Reference < io::XInputStream >& xStream, |
314 | | const uno::Reference< uno::XComponentContext >& rxContext, |
315 | | bool bRepairStorage ) |
316 | 59.8k | { |
317 | 59.8k | uno::Sequence< beans::PropertyValue > aProps( bRepairStorage ? 2 : 1 ); |
318 | 59.8k | auto pProps = aProps.getArray(); |
319 | 59.8k | pProps[0].Name = "StorageFormat"; |
320 | 59.8k | pProps[0].Value <<= aFormat; |
321 | 59.8k | if ( bRepairStorage ) |
322 | 0 | { |
323 | 0 | pProps[1].Name = "RepairPackage"; |
324 | 0 | pProps[1].Value <<= bRepairStorage; |
325 | 0 | } |
326 | | |
327 | 59.8k | uno::Sequence< uno::Any > aArgs{ uno::Any(xStream), uno::Any(embed::ElementModes::READ), uno::Any(aProps) }; |
328 | 59.8k | uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( rxContext )->createInstanceWithArguments( aArgs ), |
329 | 59.8k | uno::UNO_QUERY_THROW ); |
330 | 59.8k | return xTempStorage; |
331 | 59.8k | } |
332 | | |
333 | | |
334 | | uno::Reference< embed::XStorage > OStorageHelper::GetStorageOfFormatFromStream( |
335 | | const OUString& aFormat, |
336 | | const uno::Reference < io::XStream >& xStream, |
337 | | sal_Int32 nStorageMode, |
338 | | const uno::Reference< uno::XComponentContext >& rxContext, |
339 | | bool bRepairStorage ) |
340 | 0 | { |
341 | 0 | uno::Sequence< beans::PropertyValue > aProps( bRepairStorage ? 2 : 1 ); |
342 | 0 | auto pProps = aProps.getArray(); |
343 | 0 | pProps[0].Name = "StorageFormat"; |
344 | 0 | pProps[0].Value <<= aFormat; |
345 | 0 | if ( bRepairStorage ) |
346 | 0 | { |
347 | 0 | pProps[1].Name = "RepairPackage"; |
348 | 0 | pProps[1].Value <<= bRepairStorage; |
349 | 0 | } |
350 | |
|
351 | 0 | uno::Sequence< uno::Any > aArgs{ uno::Any(xStream), uno::Any(nStorageMode), uno::Any(aProps) }; |
352 | 0 | uno::Reference< embed::XStorage > xTempStorage( GetStorageFactory( rxContext )->createInstanceWithArguments( aArgs ), |
353 | 0 | uno::UNO_QUERY_THROW ); |
354 | 0 | return xTempStorage; |
355 | 0 | } |
356 | | |
357 | | |
358 | | uno::Sequence< beans::NamedValue > OStorageHelper::CreatePackageEncryptionData( std::u16string_view aPassword ) |
359 | 45 | { |
360 | | // TODO/LATER: Should not the method be part of DocPasswordHelper? |
361 | 45 | uno::Sequence< beans::NamedValue > aEncryptionData; |
362 | 45 | if ( !aPassword.empty() ) |
363 | 45 | { |
364 | 45 | sal_Int32 nSha1Ind = 0; |
365 | | // generate SHA256 start key |
366 | 45 | try |
367 | 45 | { |
368 | 45 | OString aUTF8Password( OUStringToOString( aPassword, RTL_TEXTENCODING_UTF8 ) ); |
369 | 45 | std::vector<unsigned char> const hash(comphelper::Hash::calculateHash( |
370 | 45 | aUTF8Password.getStr(), aUTF8Password.getLength(), |
371 | 45 | comphelper::HashType::SHA256)); |
372 | 45 | uno::Sequence<sal_Int8> aDigest(reinterpret_cast<const sal_Int8*>(hash.data()), hash.size()); |
373 | | |
374 | 45 | ++nSha1Ind; |
375 | 45 | aEncryptionData = { { PACKAGE_ENCRYPTIONDATA_SHA256UTF8, uno::Any(aDigest) } }; |
376 | 45 | } |
377 | 45 | catch ( uno::Exception& ) |
378 | 45 | { |
379 | 0 | TOOLS_WARN_EXCEPTION("comphelper", "Can not create SHA256 digest!" ); |
380 | 0 | throw; // tdf#159519 DO NOT RETURN SUCCESS |
381 | 0 | } |
382 | | |
383 | | // MS_1252 encoding was used for SO60 document format password encoding, |
384 | | // this encoding supports only a minor subset of nonascii characters, |
385 | | // but for compatibility reasons it has to be used for old document formats |
386 | 45 | aEncryptionData.realloc( nSha1Ind + 3 ); |
387 | 45 | auto pEncryptionData = aEncryptionData.getArray(); |
388 | | // these are StarOffice not-quite-SHA1 |
389 | 45 | pEncryptionData[nSha1Ind].Name = PACKAGE_ENCRYPTIONDATA_SHA1UTF8; |
390 | 45 | pEncryptionData[nSha1Ind + 1].Name = PACKAGE_ENCRYPTIONDATA_SHA1MS1252; |
391 | | |
392 | 45 | rtl_TextEncoding const pEncoding[2] = { RTL_TEXTENCODING_UTF8, RTL_TEXTENCODING_MS_1252 }; |
393 | | |
394 | 135 | for ( sal_Int32 nInd = 0; nInd < 2; nInd++ ) |
395 | 90 | { |
396 | 90 | OString aByteStrPass = OUStringToOString( aPassword, pEncoding[nInd] ); |
397 | | |
398 | 90 | sal_uInt8 pBuffer[RTL_DIGEST_LENGTH_SHA1]; |
399 | 90 | rtlDigestError nError = rtl_digest_SHA1( aByteStrPass.getStr(), |
400 | 90 | aByteStrPass.getLength(), |
401 | 90 | pBuffer, |
402 | 90 | RTL_DIGEST_LENGTH_SHA1 ); |
403 | | |
404 | 90 | if ( nError != rtl_Digest_E_None ) |
405 | 0 | { |
406 | 0 | aEncryptionData.realloc( nSha1Ind ); |
407 | 0 | return aEncryptionData; |
408 | 0 | } |
409 | | |
410 | 90 | pEncryptionData[nSha1Ind+nInd].Value <<= uno::Sequence< sal_Int8 >( reinterpret_cast<sal_Int8*>(pBuffer), RTL_DIGEST_LENGTH_SHA1 ); |
411 | 90 | } |
412 | | |
413 | | // actual SHA1 |
414 | 45 | pEncryptionData[nSha1Ind + 2].Name = PACKAGE_ENCRYPTIONDATA_SHA1CORRECT; |
415 | 45 | OString aByteStrPass = OUStringToOString(aPassword, RTL_TEXTENCODING_UTF8); |
416 | 45 | std::vector<unsigned char> const sha1(::comphelper::Hash::calculateHash( |
417 | 45 | aByteStrPass.getStr(), aByteStrPass.getLength(), |
418 | 45 | ::comphelper::HashType::SHA1)); |
419 | 45 | pEncryptionData[nSha1Ind + 2].Value <<= uno::Sequence<sal_Int8>( |
420 | 45 | reinterpret_cast<sal_Int8 const*>(sha1.data()), sha1.size()); |
421 | 45 | } |
422 | | |
423 | 45 | return aEncryptionData; |
424 | 45 | } |
425 | | |
426 | | uno::Sequence<beans::NamedValue> |
427 | | OStorageHelper::CreateGpgPackageEncryptionData(const css::uno::Reference<css::awt::XWindow>& |
428 | | #if HAVE_FEATURE_GPGME |
429 | | xParentWindow |
430 | | #endif |
431 | | ) |
432 | 0 | { |
433 | | #if HAVE_FEATURE_GPGME |
434 | | // generate session key |
435 | | // -------------------- |
436 | | |
437 | | // get 32 random chars out of it |
438 | | uno::Sequence < sal_Int8 > aVector(32); |
439 | | if (rtl_random_getBytes(nullptr, aVector.getArray(), aVector.getLength()) != rtl_Random_E_None) |
440 | | { |
441 | | throw uno::RuntimeException(u"rtl_random_getBytes failed"_ustr); |
442 | | } |
443 | | |
444 | | std::vector< uno::Sequence< beans::NamedValue > > aGpgEncryptions; |
445 | | |
446 | | uno::Reference< security::XDocumentDigitalSignatures > xSigner( |
447 | | // here none of the version-dependent methods are called |
448 | | security::DocumentDigitalSignatures::createDefault( |
449 | | comphelper::getProcessComponentContext())); |
450 | | |
451 | | xSigner->setParentWindow(xParentWindow); |
452 | | |
453 | | // fire up certificate chooser dialog - user can multi-select! |
454 | | const uno::Sequence< uno::Reference< security::XCertificate > > xSignCertificates= |
455 | | xSigner->chooseEncryptionCertificate(css::security::CertificateKind_OPENPGP); |
456 | | |
457 | | if (!xSignCertificates.hasElements()) |
458 | | return uno::Sequence< beans::NamedValue >(); // user cancelled |
459 | | |
460 | | // generate one encrypted key entry for each recipient |
461 | | // --------------------------------------------------- |
462 | | |
463 | | std::unique_ptr<GpgME::Context> ctx; |
464 | | GpgME::Error err = GpgME::checkEngine(GpgME::OpenPGP); |
465 | | if (err) |
466 | | throw uno::RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr); |
467 | | |
468 | | bool bResetContext = true; |
469 | | for (const auto & cert : xSignCertificates) |
470 | | { |
471 | | if (bResetContext) |
472 | | { |
473 | | bResetContext = false; |
474 | | ctx.reset( GpgME::Context::createForProtocol(GpgME::OpenPGP) ); |
475 | | if (ctx == nullptr) |
476 | | throw uno::RuntimeException(u"The GpgME library failed to initialize for the OpenPGP protocol."_ustr); |
477 | | ctx->setArmor(false); |
478 | | } |
479 | | |
480 | | OString aKeyID; |
481 | | if (cert.is()) |
482 | | { |
483 | | aKeyID |
484 | | = OUStringToOString(comphelper::xmlsec::GetHexString(cert->getSHA1Thumbprint(), ""), |
485 | | RTL_TEXTENCODING_UTF8); |
486 | | } |
487 | | |
488 | | std::vector<GpgME::Key> keys{ ctx->key(aKeyID.getStr(), err, false) }; |
489 | | |
490 | | // ctx is setup now, let's encrypt the lot! |
491 | | GpgME::Data plain( |
492 | | reinterpret_cast<const char*>(aVector.getConstArray()), |
493 | | size_t(aVector.getLength()), false); |
494 | | GpgME::Data cipher; |
495 | | |
496 | | GpgME::EncryptionResult crypt_res = ctx->encrypt( |
497 | | keys, plain, |
498 | | cipher, GpgME::Context::NoCompress); |
499 | | |
500 | | // tdf#160184 ask user if they want to trust an untrusted certificate |
501 | | // gpgme contexts uses the "auto" trust model by default which only |
502 | | // allows encrypting with keys that have their trust level set to |
503 | | // "Ultimate". The gpg command, however, gives the user the option |
504 | | // to encrypt with a certificate that has a lower trust level so |
505 | | // emulate that behavior by asking the user if they want to trust |
506 | | // the certificate for just this operation only. |
507 | | if (crypt_res.error().code() == GPG_ERR_UNUSABLE_PUBKEY) |
508 | | { |
509 | | if (xSigner->trustUntrustedCertificate(cert)) |
510 | | { |
511 | | // Reset the trust model back to "auto" before processing |
512 | | // the next certificate |
513 | | bResetContext = true; |
514 | | |
515 | | ctx->setFlag("trust-model", "tofu+pgp"); |
516 | | ctx->setFlag("tofu-default-policy", "unknown"); |
517 | | crypt_res = ctx->encrypt( |
518 | | keys, plain, |
519 | | cipher, GpgME::Context::NoCompress); |
520 | | } |
521 | | } |
522 | | |
523 | | off_t result = cipher.seek(0,SEEK_SET); |
524 | | (void) result; |
525 | | assert(result == 0); |
526 | | int len=0, curr=0; char buf; |
527 | | while( (curr=cipher.read(&buf, 1)) ) |
528 | | len += curr; |
529 | | |
530 | | if(crypt_res.error() || !len) |
531 | | throw lang::IllegalArgumentException( |
532 | | u"Not a suitable key, or failed to encrypt."_ustr, |
533 | | css::uno::Reference<css::uno::XInterface>(), -1); |
534 | | |
535 | | uno::Sequence < sal_Int8 > aCipherValue(len); |
536 | | result = cipher.seek(0,SEEK_SET); |
537 | | assert(result == 0); |
538 | | if( cipher.read(aCipherValue.getArray(), len) != len ) |
539 | | throw uno::RuntimeException(u"The GpgME library failed to read the encrypted value."_ustr); |
540 | | |
541 | | SAL_INFO("comphelper.crypto", "Generated gpg crypto of length: " << len); |
542 | | |
543 | | uno::Sequence<sal_Int8> aKeyIdSequence |
544 | | = comphelper::arrayToSequence<sal_Int8>(aKeyID.getStr(), aKeyID.getLength() + 1); |
545 | | uno::Sequence<beans::NamedValue> aGpgEncryptionEntry{ |
546 | | { u"KeyId"_ustr, uno::Any(aKeyIdSequence) }, |
547 | | { u"KeyPacket"_ustr, uno::Any(aKeyIdSequence) }, |
548 | | { u"CipherValue"_ustr, uno::Any(aCipherValue) } |
549 | | }; |
550 | | |
551 | | aGpgEncryptions.push_back(aGpgEncryptionEntry); |
552 | | } |
553 | | |
554 | | uno::Sequence<beans::NamedValue> aEncryptionData |
555 | | = { { PACKAGE_ENCRYPTIONDATA_SHA256UTF8, uno::Any(aVector) } }; |
556 | | |
557 | | uno::Sequence<beans::NamedValue> aContainer |
558 | | = { { u"GpgInfos"_ustr, uno::Any(comphelper::containerToSequence(aGpgEncryptions)) }, |
559 | | { u"EncryptionKey"_ustr, uno::Any(aEncryptionData) } }; |
560 | | |
561 | | return aContainer; |
562 | | #else |
563 | 0 | return uno::Sequence< beans::NamedValue >(); |
564 | 0 | #endif |
565 | 0 | } |
566 | | |
567 | | bool OStorageHelper::IsValidZipEntryFileName( std::u16string_view aName, bool bSlashAllowed ) |
568 | 1.42M | { |
569 | 1.42M | long nDots{0}; |
570 | 23.1M | for ( size_t i = 0; i < aName.size(); i++ ) |
571 | 21.7M | { |
572 | 21.7M | switch ( aName[i] ) |
573 | 21.7M | { |
574 | 1.32M | case '.': |
575 | 1.32M | if (nDots != -1) |
576 | 64.1k | { |
577 | 64.1k | ++nDots; |
578 | 64.1k | } |
579 | 1.32M | break; |
580 | 6 | case '\\': |
581 | 11 | case '?': |
582 | 17 | case '<': |
583 | 22 | case '>': |
584 | 26 | case '\"': |
585 | 31 | case '|': |
586 | 36 | case ':': |
587 | 36 | return false; |
588 | 719k | case '/': |
589 | 719k | if (!bSlashAllowed || nDots == 1 || nDots == 2 || i == 0) |
590 | 5 | return false; |
591 | 719k | nDots = 0; |
592 | 719k | break; |
593 | 19.6M | default: |
594 | 19.6M | nDots = -1; |
595 | 19.6M | if ( aName[i] < 32 || (aName[i] >= 0xD800 && aName[i] <= 0xDFFF) ) |
596 | 35 | return false; |
597 | 21.7M | } |
598 | 21.7M | } |
599 | 1.42M | return nDots != 1 && nDots != 2; |
600 | 1.42M | } |
601 | | |
602 | | |
603 | | bool OStorageHelper::PathHasSegment( std::u16string_view aPath, std::u16string_view aSegment ) |
604 | 0 | { |
605 | 0 | bool bResult = false; |
606 | 0 | const size_t nPathLen = aPath.size(); |
607 | 0 | const size_t nSegLen = aSegment.size(); |
608 | |
|
609 | 0 | if ( !aSegment.empty() && nPathLen >= nSegLen ) |
610 | 0 | { |
611 | 0 | OUString aEndSegment = OUString::Concat("/") + aSegment; |
612 | 0 | OUString aInternalSegment = aEndSegment + "/"; |
613 | |
|
614 | 0 | if ( aPath.find( aInternalSegment ) != std::u16string_view::npos ) |
615 | 0 | bResult = true; |
616 | |
|
617 | 0 | if ( !bResult && o3tl::starts_with(aPath, aSegment ) ) |
618 | 0 | { |
619 | 0 | if ( nPathLen == nSegLen || aPath[nSegLen] == '/' ) |
620 | 0 | bResult = true; |
621 | 0 | } |
622 | |
|
623 | 0 | if ( !bResult && nPathLen > nSegLen && aPath.substr( nPathLen - nSegLen - 1, nSegLen + 1 ) == aEndSegment ) |
624 | 0 | bResult = true; |
625 | 0 | } |
626 | |
|
627 | 0 | return bResult; |
628 | 0 | } |
629 | | |
630 | | class LifecycleProxy::Impl |
631 | | : public std::vector< uno::Reference< embed::XStorage > > {}; |
632 | | LifecycleProxy::LifecycleProxy() |
633 | 24.3k | : m_xBadness( new Impl ) { } |
634 | 24.3k | LifecycleProxy::~LifecycleProxy() { } |
635 | | |
636 | | void LifecycleProxy::commitStorages() |
637 | 0 | { |
638 | 0 | std::for_each(m_xBadness->rbegin(), m_xBadness->rend(), // reverse order (outwards) |
639 | 0 | [](Impl::reference rxItem) { |
640 | 0 | uno::Reference<embed::XTransactedObject> const xTransaction(rxItem, uno::UNO_QUERY); |
641 | 0 | if (xTransaction.is()) |
642 | 0 | { |
643 | 0 | xTransaction->commit(); |
644 | 0 | } |
645 | 0 | }); |
646 | 0 | } |
647 | | |
648 | | static void splitPath( std::vector<OUString> &rElems, std::u16string_view rPath ) |
649 | 0 | { |
650 | 0 | for (sal_Int32 i = 0; i >= 0;) |
651 | 0 | rElems.push_back( OUString(o3tl::getToken(rPath, 0, '/', i )) ); |
652 | 0 | } |
653 | | |
654 | | static uno::Reference< embed::XStorage > LookupStorageAtPath( |
655 | | const uno::Reference< embed::XStorage > &xParentStorage, |
656 | | std::vector<OUString> &rElems, sal_uInt32 nOpenMode, |
657 | | LifecycleProxy const &rNastiness ) |
658 | 0 | { |
659 | 0 | uno::Reference< embed::XStorage > xStorage( xParentStorage ); |
660 | 0 | rNastiness.m_xBadness->push_back( xStorage ); |
661 | 0 | for( size_t i = 0; i < rElems.size() && xStorage.is(); i++ ) |
662 | 0 | { |
663 | 0 | xStorage = xStorage->openStorageElement( rElems[i], nOpenMode ); |
664 | 0 | rNastiness.m_xBadness->push_back( xStorage ); |
665 | 0 | } |
666 | 0 | return xStorage; |
667 | 0 | } |
668 | | |
669 | | uno::Reference< embed::XStorage > OStorageHelper::GetStorageAtPath( |
670 | | const uno::Reference< embed::XStorage > &xStorage, |
671 | | std::u16string_view rPath, sal_uInt32 nOpenMode, |
672 | | LifecycleProxy const &rNastiness ) |
673 | 0 | { |
674 | 0 | std::vector<OUString> aElems; |
675 | 0 | splitPath( aElems, rPath ); |
676 | 0 | return LookupStorageAtPath( xStorage, aElems, nOpenMode, rNastiness ); |
677 | 0 | } |
678 | | |
679 | | uno::Reference< io::XStream > OStorageHelper::GetStreamAtPath( |
680 | | const uno::Reference< embed::XStorage > &xParentStorage, |
681 | | std::u16string_view rPath, sal_uInt32 nOpenMode, |
682 | | LifecycleProxy const &rNastiness ) |
683 | 0 | { |
684 | 0 | std::vector<OUString> aElems; |
685 | 0 | splitPath( aElems, rPath ); |
686 | 0 | OUString aName( aElems.back() ); |
687 | 0 | aElems.pop_back(); |
688 | 0 | sal_uInt32 nStorageMode = nOpenMode & ~embed::ElementModes::TRUNCATE; |
689 | 0 | uno::Reference< embed::XStorage > xStorage( |
690 | 0 | LookupStorageAtPath( xParentStorage, aElems, nStorageMode, rNastiness ), |
691 | 0 | uno::UNO_SET_THROW ); |
692 | 0 | return xStorage->openStreamElement( aName, nOpenMode ); |
693 | 0 | } |
694 | | |
695 | | uno::Reference< io::XStream > OStorageHelper::GetStreamAtPackageURL( |
696 | | uno::Reference< embed::XStorage > const& xParentStorage, |
697 | | const OUString& rURL, sal_uInt32 const nOpenMode, |
698 | | LifecycleProxy const & rNastiness) |
699 | 0 | { |
700 | 0 | std::u16string_view path; |
701 | 0 | if (rURL.startsWithIgnoreAsciiCase("vnd.sun.star.Package:", &path)) |
702 | 0 | { |
703 | 0 | return GetStreamAtPath(xParentStorage, path, nOpenMode, rNastiness); |
704 | 0 | } |
705 | 0 | return nullptr; |
706 | 0 | } |
707 | | |
708 | | OUString OStorageHelper::GetODFVersionFromStorage(const uno::Reference<embed::XStorage>& xStorage) |
709 | 0 | { |
710 | 0 | OUString aODFVersion; |
711 | 0 | try |
712 | 0 | { |
713 | 0 | uno::Reference<beans::XPropertySet> xPropSet(xStorage, uno::UNO_QUERY); |
714 | 0 | if (xPropSet) |
715 | 0 | xPropSet->getPropertyValue(u"Version"_ustr) >>= aODFVersion; |
716 | 0 | } |
717 | 0 | catch (uno::Exception&) |
718 | 0 | { |
719 | 0 | } |
720 | 0 | return aODFVersion; |
721 | 0 | } |
722 | | } |
723 | | |
724 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |