LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / svl / source / passwordcontainer / passwordcontainer.cxx
blob6bbb01497a301ecdf133a7dac91c701d1e2b0966
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
23 #include <string_view>
25 #include "passwordcontainer.hxx"
27 #include <cppuhelper/factory.hxx>
28 #include <cppuhelper/supportsservice.hxx>
29 #include <comphelper/processfactory.hxx>
30 #include <comphelper/propertyvalue.hxx>
31 #include <comphelper/sequence.hxx>
32 #include <com/sun/star/beans/PropertyValue.hpp>
33 #include <com/sun/star/task/InteractionHandler.hpp>
34 #include <com/sun/star/task/MasterPasswordRequest.hpp>
35 #include <com/sun/star/task/NoMasterException.hpp>
36 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
38 #include <osl/diagnose.h>
39 #include <rtl/character.hxx>
40 #include <rtl/cipher.h>
41 #include <rtl/digest.h>
42 #include <rtl/byteseq.hxx>
43 #include <rtl/ustrbuf.hxx>
45 using namespace osl;
46 using namespace utl;
47 using namespace com::sun::star;
48 using namespace com::sun::star::uno;
49 using namespace com::sun::star::registry;
50 using namespace com::sun::star::lang;
51 using namespace com::sun::star::task;
52 using namespace com::sun::star::ucb;
54 static OUString createIndex(const std::vector< OUString >& lines)
56 OUStringBuffer aResult;
58 for( size_t i = 0; i < lines.size(); i++ )
60 if( i )
61 aResult.append("__");
62 OString line = OUStringToOString( lines[i], RTL_TEXTENCODING_UTF8 );
63 const char* pLine = line.getStr();
65 while( *pLine )
67 if (rtl::isAsciiAlphanumeric(static_cast<unsigned char>(*pLine)))
69 aResult.append(*pLine);
71 else
73 aResult.append("_" + OUString::number(*pLine, 16) );
76 pLine++;
80 return aResult.makeStringAndClear();
84 static std::vector< OUString > getInfoFromInd( std::u16string_view aInd )
86 std::vector< OUString > aResult;
87 bool aStart = true;
89 OString line = OUStringToOString( aInd, RTL_TEXTENCODING_ASCII_US );
90 const char* pLine = line.getStr();
93 OUStringBuffer newItem;
94 if( !aStart )
95 pLine += 2;
96 else
97 aStart = false;
99 while( *pLine && ( pLine[0] != '_' || pLine[1] != '_' ))
100 if( *pLine != '_' )
102 newItem.append( *pLine );
103 pLine++;
105 else
107 OUString aNum;
108 for( int i = 1; i < 3; i++ )
110 if( !pLine[i]
111 || ( ( pLine[i] < '0' || pLine[i] > '9' )
112 && ( pLine[i] < 'a' || pLine[i] > 'f' )
113 && ( pLine[i] < 'A' || pLine[i] > 'F' ) ) )
115 OSL_FAIL( "Wrong index syntax!" );
116 return aResult;
119 aNum += OUStringChar( pLine[i] );
122 newItem.append( sal_Unicode( aNum.toUInt32( 16 ) ) );
123 pLine += 3;
126 aResult.push_back( newItem.makeStringAndClear() );
127 } while( pLine[0] == '_' && pLine[1] == '_' );
129 if( *pLine )
130 OSL_FAIL( "Wrong index syntax!" );
132 return aResult;
136 static bool shorterUrl( OUString& aURL )
138 sal_Int32 aInd = aURL.lastIndexOf( '/' );
139 if( aInd > 0 && aURL.indexOf( "://" ) != aInd-2 )
141 aURL = aURL.copy( 0, aInd );
142 return true;
145 return false;
149 static OUString getAsciiLine( const ::rtl::ByteSequence& buf )
151 OUString aResult;
153 ::rtl::ByteSequence outbuf( buf.getLength()*2+1 );
155 for( int ind = 0; ind < buf.getLength(); ind++ )
157 outbuf[ind*2] = ( static_cast<sal_uInt8>(buf[ind]) >> 4 ) + 'a';
158 outbuf[ind*2+1] = ( static_cast<sal_uInt8>(buf[ind]) & 0x0f ) + 'a';
160 outbuf[buf.getLength()*2] = '\0';
162 aResult = OUString::createFromAscii( reinterpret_cast<char*>(outbuf.getArray()) );
164 return aResult;
168 static ::rtl::ByteSequence getBufFromAsciiLine( const OUString& line )
170 OSL_ENSURE( line.getLength() % 2 == 0, "Wrong syntax!" );
171 OString tmpLine = OUStringToOString( line, RTL_TEXTENCODING_ASCII_US );
172 ::rtl::ByteSequence aResult(line.getLength()/2);
174 for( int ind = 0; ind < tmpLine.getLength()/2; ind++ )
176 aResult[ind] = ( static_cast<sal_uInt8>( tmpLine[ind*2] - 'a' ) << 4 ) | static_cast<sal_uInt8>( tmpLine[ind*2+1] - 'a' );
179 return aResult;
183 PasswordMap StorageItem::getInfo()
185 PasswordMap aResult;
187 const Sequence< OUString > aNodeNames = ConfigItem::GetNodeNames( "Store" );
188 sal_Int32 aNodeCount = aNodeNames.getLength();
189 Sequence< OUString > aPropNames( aNodeCount * 2);
191 std::transform(aNodeNames.begin(), aNodeNames.end(), aPropNames.getArray(),
192 [](const OUString& rName) -> OUString {
193 return "Store/Passwordstorage['" + rName + "']/Password"; });
194 std::transform(aNodeNames.begin(), aNodeNames.end(), aPropNames.getArray() + aNodeCount,
195 [](const OUString& rName) -> OUString {
196 return "Store/Passwordstorage['" + rName + "']/InitializationVector"; });
198 Sequence< Any > aPropertyValues = ConfigItem::GetProperties( aPropNames );
200 if( aPropertyValues.getLength() != aNodeCount * 2)
202 OSL_FAIL( "Problems during reading" );
203 return aResult;
206 for( sal_Int32 aNodeInd = 0; aNodeInd < aNodeCount; ++aNodeInd )
208 std::vector< OUString > aUrlUsr = getInfoFromInd( aNodeNames[aNodeInd] );
210 if( aUrlUsr.size() == 2 )
212 OUString aUrl = aUrlUsr[0];
213 OUString aName = aUrlUsr[1];
215 OUString aEPasswd;
216 OUString aIV;
217 aPropertyValues[aNodeInd] >>= aEPasswd;
218 aPropertyValues[aNodeInd + aNodeCount] >>= aIV;
220 PasswordMap::iterator aIter = aResult.find( aUrl );
221 if( aIter != aResult.end() )
222 aIter->second.emplace_back( aName, aEPasswd, aIV );
223 else
225 NamePasswordRecord aNewRecord( aName, aEPasswd, aIV );
226 std::vector< NamePasswordRecord > listToAdd( 1, aNewRecord );
228 aResult.insert( PairUrlRecord( aUrl, listToAdd ) );
231 else
232 OSL_FAIL( "Wrong index syntax!" );
235 return aResult;
239 void StorageItem::setUseStorage( bool bUse )
241 ConfigItem::SetModified();
242 ConfigItem::PutProperties( { "UseStorage" }, { uno::Any(bUse) } );
246 bool StorageItem::useStorage()
248 Sequence<OUString> aNodeNames { "UseStorage" };
250 Sequence< Any > aPropertyValues = ConfigItem::GetProperties( aNodeNames );
252 if( aPropertyValues.getLength() != aNodeNames.getLength() )
254 OSL_FAIL( "Problems during reading" );
255 return false;
258 bool aResult = false;
259 aPropertyValues[0] >>= aResult;
261 return aResult;
265 sal_Int32 StorageItem::getStorageVersion()
267 Sequence<OUString> aNodeNames { "StorageVersion" };
269 Sequence< Any > aPropertyValues = ConfigItem::GetProperties( aNodeNames );
271 if( aPropertyValues.getLength() != aNodeNames.getLength() )
273 OSL_FAIL( "Problems during reading" );
274 return 0;
277 sal_Int32 nResult = 0;
278 aPropertyValues[0] >>= nResult;
280 return nResult;
283 bool StorageItem::getEncodedMasterPassword( OUString& aResult, OUString& aResultIV )
285 if( hasEncoded )
287 aResult = mEncoded;
288 aResultIV = mEncodedIV;
289 return true;
292 Sequence< OUString > aNodeNames{ "HasMaster", "Master", "MasterInitializationVector" };
294 Sequence< Any > aPropertyValues = ConfigItem::GetProperties( aNodeNames );
296 if( aPropertyValues.getLength() != aNodeNames.getLength() )
298 OSL_FAIL( "Problems during reading" );
299 return false;
302 aPropertyValues[0] >>= hasEncoded;
303 aPropertyValues[1] >>= mEncoded;
304 aPropertyValues[2] >>= mEncodedIV;
306 aResult = mEncoded;
307 aResultIV = mEncodedIV;
309 return hasEncoded;
313 void StorageItem::setEncodedMasterPassword( const OUString& aEncoded, const OUString& aEncodedIV, bool bAcceptEmpty )
315 bool bHasMaster = ( !aEncoded.isEmpty() || bAcceptEmpty );
317 ConfigItem::SetModified();
318 ConfigItem::PutProperties( { "HasMaster", "Master", "MasterInitializationVector", "StorageVersion" },
319 { uno::Any(bHasMaster), uno::Any(aEncoded),
320 uno::Any(aEncodedIV), uno::Any(nCurrentStorageVersion) } );
322 hasEncoded = bHasMaster;
323 mEncoded = aEncoded;
324 mEncodedIV = aEncodedIV;
328 void StorageItem::remove( const OUString& aURL, const OUString& aName )
330 Sequence< OUString > sendSeq { createIndex( { aURL, aName } ) };
332 ConfigItem::ClearNodeElements( "Store", sendSeq );
336 void StorageItem::clear()
338 ConfigItem::ClearNodeSet( "Store" );
342 void StorageItem::update( const OUString& aURL, const NamePasswordRecord& aRecord )
344 if ( !aRecord.HasPasswords( PERSISTENT_RECORD ) )
346 OSL_FAIL( "Unexpected storing of a record!" );
347 return;
350 Sequence< beans::PropertyValue > sendSeq{ comphelper::makePropertyValue(
351 "Store/Passwordstorage['" + createIndex( { aURL, aRecord.GetUserName() } ) + "']/InitializationVector",
352 aRecord.GetPersistentIV()), comphelper::makePropertyValue(
353 "Store/Passwordstorage['" + createIndex( { aURL, aRecord.GetUserName() } ) + "']/Password",
354 aRecord.GetPersistentPasswords()) };
356 ConfigItem::SetModified();
357 ConfigItem::SetSetProperties( "Store", sendSeq );
361 void StorageItem::Notify( const Sequence< OUString >& )
363 // this feature still should not be used
364 if( mainCont )
365 mainCont->Notify();
369 void StorageItem::ImplCommit()
371 // Do nothing, we stored everything we want already
375 PasswordContainer::PasswordContainer( const Reference<XComponentContext>& rxContext )
377 // m_pStorageFile->Notify() can be called
378 ::osl::MutexGuard aGuard( mMutex );
380 mComponent.set( rxContext->getServiceManager(), UNO_QUERY );
381 mComponent->addEventListener( this );
383 m_xStorageFile.emplace( this, "Office.Common/Passwords" );
384 if( m_xStorageFile->useStorage() )
385 m_aContainer = m_xStorageFile->getInfo();
389 PasswordContainer::~PasswordContainer()
391 ::osl::MutexGuard aGuard( mMutex );
393 m_xStorageFile.reset();
395 if( mComponent.is() )
397 mComponent->removeEventListener(this);
398 mComponent.clear();
402 void SAL_CALL PasswordContainer::disposing( const EventObject& )
404 ::osl::MutexGuard aGuard( mMutex );
406 m_xStorageFile.reset();
408 if( mComponent.is() )
410 //mComponent->removeEventListener(this);
411 mComponent.clear();
415 std::vector< OUString > PasswordContainer::DecodePasswords( const OUString& aLine, const OUString& aIV, const OUString& aMasterPasswd, css::task::PasswordRequestMode mode )
417 if( !aMasterPasswd.isEmpty() )
419 rtlCipher aDecoder = rtl_cipher_create (rtl_Cipher_AlgorithmBF, rtl_Cipher_ModeStream );
420 OSL_ENSURE( aDecoder, "Can't create decoder" );
422 if( aDecoder )
424 OSL_ENSURE( aMasterPasswd.getLength() == RTL_DIGEST_LENGTH_MD5 * 2, "Wrong master password format!" );
426 unsigned char code[RTL_DIGEST_LENGTH_MD5];
427 for( int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ind++ )
428 code[ ind ] = static_cast<char>(aMasterPasswd.copy( ind*2, 2 ).toUInt32(16));
430 unsigned char iv[RTL_DIGEST_LENGTH_MD5] = {0};
431 if (!aIV.isEmpty())
433 for( int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ind++ )
434 iv[ ind ] = static_cast<char>(aIV.copy( ind*2, 2 ).toUInt32(16));
437 rtlCipherError result = rtl_cipher_init (
438 aDecoder, rtl_Cipher_DirectionDecode,
439 code, RTL_DIGEST_LENGTH_MD5, iv, RTL_DIGEST_LENGTH_MD5 );
441 if( result == rtl_Cipher_E_None )
443 ::rtl::ByteSequence aSeq = getBufFromAsciiLine( aLine );
445 ::rtl::ByteSequence resSeq( aSeq.getLength() );
447 rtl_cipher_decode ( aDecoder, aSeq.getArray(), aSeq.getLength(),
448 reinterpret_cast<sal_uInt8*>(resSeq.getArray()), resSeq.getLength() );
450 OUString aPasswd( reinterpret_cast<char*>(resSeq.getArray()), resSeq.getLength(), RTL_TEXTENCODING_UTF8 );
452 rtl_cipher_destroy (aDecoder);
454 return getInfoFromInd( aPasswd );
457 rtl_cipher_destroy (aDecoder);
460 else
462 OSL_FAIL( "No master password provided!" );
463 // throw special exception
466 // problems with decoding
467 OSL_FAIL( "Problem with decoding" );
468 throw css::task::NoMasterException(
469 "Can't decode!", css::uno::Reference<css::uno::XInterface>(), mode);
472 OUString PasswordContainer::EncodePasswords(const std::vector< OUString >& lines, const OUString& aIV, const OUString& aMasterPasswd)
474 if( !aMasterPasswd.isEmpty() )
476 OString aSeq = OUStringToOString( createIndex( lines ), RTL_TEXTENCODING_UTF8 );
478 rtlCipher aEncoder = rtl_cipher_create (rtl_Cipher_AlgorithmBF, rtl_Cipher_ModeStream );
479 OSL_ENSURE( aEncoder, "Can't create encoder" );
481 if( aEncoder )
483 OSL_ENSURE( aMasterPasswd.getLength() == RTL_DIGEST_LENGTH_MD5 * 2, "Wrong master password format!" );
485 unsigned char code[RTL_DIGEST_LENGTH_MD5];
486 for( int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ind++ )
487 code[ ind ] = static_cast<char>(aMasterPasswd.copy( ind*2, 2 ).toUInt32(16));
489 unsigned char iv[RTL_DIGEST_LENGTH_MD5] = {0};
490 if (!aIV.isEmpty())
492 for( int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ind++ )
493 iv[ ind ] = static_cast<char>(aIV.copy( ind*2, 2 ).toUInt32(16));
496 rtlCipherError result = rtl_cipher_init (
497 aEncoder, rtl_Cipher_DirectionEncode,
498 code, RTL_DIGEST_LENGTH_MD5, iv, RTL_DIGEST_LENGTH_MD5 );
500 if( result == rtl_Cipher_E_None )
502 ::rtl::ByteSequence resSeq(aSeq.getLength()+1);
504 result = rtl_cipher_encode ( aEncoder, aSeq.getStr(), aSeq.getLength()+1,
505 reinterpret_cast<sal_uInt8*>(resSeq.getArray()), resSeq.getLength() );
508 //test
509 rtlCipherError result = rtl_cipher_init (
510 aEncoder, rtl_Cipher_DirectionDecode,
511 code, RTL_DIGEST_LENGTH_MD5, NULL, 0 );
514 if( result == rtl_Cipher_E_None )
516 OUString testOU = getAsciiLine( resSeq );
517 ::rtl::ByteSequence aSeq1 = getBufFromAsciiLine( testOU );
519 ::rtl::ByteSequence resSeq1( aSeq1.getLength() );
521 if( resSeq.getLength() == aSeq1.getLength() )
523 for( int ind = 0; ind < aSeq1.getLength(); ind++ )
524 if( resSeq[ind] != aSeq1[ind] )
525 testOU = "";
528 result = rtl_cipher_decode ( aEncoder, (sal_uInt8*)aSeq1.getArray(), aSeq1.getLength(),
529 (sal_uInt8*)resSeq1.getArray(), resSeq1.getLength() );
531 OUString aPasswd( ( char* )resSeq1.getArray(), resSeq1.getLength(), RTL_TEXTENCODING_UTF8 );
535 rtl_cipher_destroy (aEncoder);
537 if( result == rtl_Cipher_E_None )
538 return getAsciiLine( resSeq );
542 rtl_cipher_destroy (aEncoder);
545 else
547 OSL_FAIL( "No master password provided!" );
548 // throw special exception
551 // problems with encoding
552 OSL_FAIL( "Problem with encoding" );
553 throw RuntimeException("Can't encode!" );
556 void PasswordContainer::UpdateVector( const OUString& aURL, std::vector< NamePasswordRecord >& toUpdate, NamePasswordRecord const & aRecord, bool writeFile )
558 for (auto & aNPIter : toUpdate)
559 if( aNPIter.GetUserName() == aRecord.GetUserName() )
561 if( aRecord.HasPasswords( MEMORY_RECORD ) )
562 aNPIter.SetMemoryPasswords( aRecord.GetMemoryPasswords() );
564 if( aRecord.HasPasswords( PERSISTENT_RECORD ) )
566 aNPIter.SetPersistentPasswords( aRecord.GetPersistentPasswords(), aRecord.GetPersistentIV() );
568 if( writeFile )
570 // the password must be already encoded
571 m_xStorageFile->update( aURL, aRecord ); // change existing ( aURL, aName ) record in the configfile
575 return;
579 if( aRecord.HasPasswords( PERSISTENT_RECORD ) && writeFile )
581 // the password must be already encoded
582 m_xStorageFile->update( aURL, aRecord ); // add new aName to the existing url
585 toUpdate.insert( toUpdate.begin(), aRecord );
589 UserRecord PasswordContainer::CopyToUserRecord( const NamePasswordRecord& aRecord, bool& io_bTryToDecode, const Reference< XInteractionHandler >& aHandler )
591 ::std::vector< OUString > aPasswords;
592 if( aRecord.HasPasswords( MEMORY_RECORD ) )
593 aPasswords = aRecord.GetMemoryPasswords();
595 if( io_bTryToDecode && aRecord.HasPasswords( PERSISTENT_RECORD ) )
599 ::std::vector< OUString > aDecodedPasswords = DecodePasswords( aRecord.GetPersistentPasswords(), aRecord.GetPersistentIV(),
600 GetMasterPassword( aHandler ), css::task::PasswordRequestMode_PASSWORD_ENTER );
601 aPasswords.insert( aPasswords.end(), aDecodedPasswords.begin(), aDecodedPasswords.end() );
603 catch( NoMasterException& )
605 // if master password could not be detected the entry will be just ignored
606 io_bTryToDecode = false;
610 return UserRecord( aRecord.GetUserName(), comphelper::containerToSequence( aPasswords ) );
614 Sequence< UserRecord > PasswordContainer::CopyToUserRecordSequence( const std::vector< NamePasswordRecord >& original, const Reference< XInteractionHandler >& aHandler )
616 Sequence< UserRecord > aResult( original.size() );
617 auto aResultRange = asNonConstRange(aResult);
618 sal_uInt32 nInd = 0;
619 bool bTryToDecode = true;
621 for (auto const& aNPIter : original)
623 aResultRange[nInd] = CopyToUserRecord( aNPIter, bTryToDecode, aHandler );
624 ++nInd;
627 return aResult;
631 void SAL_CALL PasswordContainer::add( const OUString& Url, const OUString& UserName, const Sequence< OUString >& Passwords, const Reference< XInteractionHandler >& aHandler )
633 ::osl::MutexGuard aGuard( mMutex );
635 PrivateAdd( Url, UserName, Passwords, MEMORY_RECORD, aHandler );
639 void SAL_CALL PasswordContainer::addPersistent( const OUString& Url, const OUString& UserName, const Sequence< OUString >& Passwords, const Reference< XInteractionHandler >& aHandler )
641 ::osl::MutexGuard aGuard( mMutex );
643 PrivateAdd( Url, UserName, Passwords, PERSISTENT_RECORD, aHandler );
646 OUString PasswordContainer::createIV()
648 rtlRandomPool randomPool = mRandomPool.get();
649 unsigned char iv[RTL_DIGEST_LENGTH_MD5];
650 rtl_random_getBytes(randomPool, iv, RTL_DIGEST_LENGTH_MD5);
651 OUStringBuffer aBuffer;
652 for (sal_uInt8 i : iv)
654 aBuffer.append(OUString::number(i >> 4, 16));
655 aBuffer.append(OUString::number(i & 15, 16));
657 return aBuffer.makeStringAndClear();
660 void PasswordContainer::PrivateAdd( const OUString& Url, const OUString& UserName, const Sequence< OUString >& Passwords, char Mode, const Reference< XInteractionHandler >& aHandler )
662 NamePasswordRecord aRecord( UserName );
663 ::std::vector< OUString > aStorePass = comphelper::sequenceToContainer< std::vector<OUString> >( Passwords );
665 if( Mode == PERSISTENT_RECORD )
667 OUString sIV = createIV();
668 OUString sEncodedPasswords = EncodePasswords(aStorePass, sIV, GetMasterPassword(aHandler));
669 aRecord.SetPersistentPasswords(sEncodedPasswords, sIV);
671 else if( Mode == MEMORY_RECORD )
672 aRecord.SetMemoryPasswords( std::move(aStorePass) );
673 else
675 OSL_FAIL( "Unexpected persistence status!" );
676 return;
679 if( !m_aContainer.empty() )
681 PasswordMap::iterator aIter = m_aContainer.find( Url );
683 if( aIter != m_aContainer.end() )
685 UpdateVector( aIter->first, aIter->second, aRecord, true );
686 return;
690 std::vector< NamePasswordRecord > listToAdd( 1, aRecord );
691 m_aContainer.insert( PairUrlRecord( Url, listToAdd ) );
693 if( Mode == PERSISTENT_RECORD && m_xStorageFile && m_xStorageFile->useStorage() )
694 m_xStorageFile->update( Url, aRecord );
699 UrlRecord SAL_CALL PasswordContainer::find( const OUString& aURL, const Reference< XInteractionHandler >& aHandler )
701 return find( aURL, u"", false, aHandler );
705 UrlRecord SAL_CALL PasswordContainer::findForName( const OUString& aURL, const OUString& aName, const Reference< XInteractionHandler >& aHandler )
707 return find( aURL, aName, true, aHandler );
711 Sequence< UserRecord > PasswordContainer::FindUsr( const std::vector< NamePasswordRecord >& userlist, std::u16string_view aName, const Reference< XInteractionHandler >& aHandler )
713 for (auto const& aNPIter : userlist)
715 if( aNPIter.GetUserName() == aName )
717 bool bTryToDecode = true;
718 Sequence< UserRecord > aResult { CopyToUserRecord( aNPIter, bTryToDecode, aHandler ) };
720 return aResult;
724 return Sequence< UserRecord >();
728 bool PasswordContainer::createUrlRecord(
729 const PasswordMap::iterator & rIter,
730 bool bName,
731 std::u16string_view aName,
732 const Reference< XInteractionHandler >& aHandler,
733 UrlRecord & rRec )
735 if ( bName )
737 Sequence< UserRecord > aUsrRec
738 = FindUsr( rIter->second, aName, aHandler );
739 if( aUsrRec.hasElements() )
741 rRec = UrlRecord( rIter->first, aUsrRec );
742 return true;
745 else
747 rRec = UrlRecord(
748 rIter->first,
749 CopyToUserRecordSequence( rIter->second, aHandler ) );
750 return true;
752 return false;
756 UrlRecord PasswordContainer::find(
757 const OUString& aURL,
758 std::u16string_view aName,
759 bool bName, // only needed to support empty user names
760 const Reference< XInteractionHandler >& aHandler )
762 ::osl::MutexGuard aGuard( mMutex );
764 if( !m_aContainer.empty() && !aURL.isEmpty() )
766 OUString aUrl( aURL );
768 // each iteration remove last '/...' section from the aUrl
769 // while it's possible, up to the most left '://'
772 // first look for <url>/somename and then look for <url>/somename/...
773 PasswordMap::iterator aIter = m_aContainer.find( aUrl );
774 if( aIter != m_aContainer.end() )
776 UrlRecord aRec;
777 if ( createUrlRecord( aIter, bName, aName, aHandler, aRec ) )
778 return aRec;
780 else
782 OUString tmpUrl( aUrl );
783 if ( !tmpUrl.endsWith("/") )
784 tmpUrl += "/";
786 aIter = m_aContainer.lower_bound( tmpUrl );
787 if( aIter != m_aContainer.end() && aIter->first.match( tmpUrl ) )
789 UrlRecord aRec;
790 if ( createUrlRecord( aIter, bName, aName, aHandler, aRec ) )
791 return aRec;
795 while( shorterUrl( aUrl ) && !aUrl.isEmpty() );
798 return UrlRecord();
801 OUString PasswordContainer::GetDefaultMasterPassword()
803 OUStringBuffer aResult;
804 for ( sal_Int32 nInd = 0; nInd < RTL_DIGEST_LENGTH_MD5; nInd++ )
805 aResult.append("aa");
807 return aResult.makeStringAndClear();
810 OUString PasswordContainer::RequestPasswordFromUser( PasswordRequestMode aRMode, const uno::Reference< task::XInteractionHandler >& xHandler )
812 // empty string means that the call was cancelled or just failed
813 OUString aResult;
815 if ( xHandler.is() )
817 ::rtl::Reference< MasterPasswordRequest_Impl > xRequest = new MasterPasswordRequest_Impl( aRMode );
819 xHandler->handle( xRequest );
821 ::rtl::Reference< ucbhelper::InteractionContinuation > xSelection = xRequest->getSelection();
823 if ( xSelection.is() )
825 Reference< XInteractionAbort > xAbort( xSelection.get(), UNO_QUERY );
826 if ( !xAbort.is() )
828 const ::rtl::Reference< ucbhelper::InteractionSupplyAuthentication > & xSupp
829 = xRequest->getAuthenticationSupplier();
831 aResult = xSupp->getPassword();
836 return aResult;
839 // Mangle the key to match an old bug
840 static OUString ReencodeAsOldHash(const OUString& rPass)
842 OUStringBuffer aBuffer;
843 for (int ind = 0; ind < RTL_DIGEST_LENGTH_MD5; ++ind)
845 unsigned char i = static_cast<char>(rPass.copy(ind * 2, 2).toUInt32(16));
846 aBuffer.append(static_cast< sal_Unicode >('a' + (i >> 4)));
847 aBuffer.append(static_cast< sal_Unicode >('a' + (i & 15)));
849 return aBuffer.makeStringAndClear();
852 OUString const & PasswordContainer::GetMasterPassword( const Reference< XInteractionHandler >& aHandler )
854 PasswordRequestMode aRMode = PasswordRequestMode_PASSWORD_ENTER;
855 if( !m_xStorageFile || !m_xStorageFile->useStorage() )
856 throw NoMasterException("Password storing is not active!", Reference< XInterface >(), aRMode );
858 if( m_aMasterPassword.isEmpty() && aHandler.is() )
860 OUString aEncodedMP, aEncodedMPIV;
861 bool bDefaultPassword = false;
863 if( !m_xStorageFile->getEncodedMasterPassword( aEncodedMP, aEncodedMPIV ) )
864 aRMode = PasswordRequestMode_PASSWORD_CREATE;
865 else if ( aEncodedMP.isEmpty() )
867 m_aMasterPassword = GetDefaultMasterPassword();
868 bDefaultPassword = true;
871 if ( !bDefaultPassword )
873 bool bAskAgain = false;
874 do {
875 bAskAgain = false;
877 OUString aPass = RequestPasswordFromUser( aRMode, aHandler );
878 if ( !aPass.isEmpty() )
880 if( aRMode == PasswordRequestMode_PASSWORD_CREATE )
882 m_aMasterPassword = aPass;
883 std::vector< OUString > aMaster( 1, m_aMasterPassword );
885 OUString sIV = createIV();
886 m_xStorageFile->setEncodedMasterPassword(EncodePasswords(aMaster, sIV, m_aMasterPassword), sIV);
888 else
890 if (m_xStorageFile->getStorageVersion() == 0)
891 aPass = ReencodeAsOldHash(aPass);
893 std::vector< OUString > aRM( DecodePasswords( aEncodedMP, aEncodedMPIV, aPass, aRMode ) );
894 if( aRM.empty() || aPass != aRM[0] )
896 bAskAgain = true;
897 aRMode = PasswordRequestMode_PASSWORD_REENTER;
899 else
900 m_aMasterPassword = aPass;
904 } while( bAskAgain );
908 if ( m_aMasterPassword.isEmpty() )
909 throw NoMasterException("No master password!", Reference< XInterface >(), aRMode );
911 return m_aMasterPassword;
915 void SAL_CALL PasswordContainer::remove( const OUString& aURL, const OUString& aName )
917 ::osl::MutexGuard aGuard( mMutex );
919 OUString aUrl( aURL );
920 if( m_aContainer.empty() )
921 return;
923 PasswordMap::iterator aIter = m_aContainer.find( aUrl );
925 if( aIter == m_aContainer.end() )
927 if( aUrl.endsWith("/") )
928 aUrl = aUrl.copy( 0, aUrl.getLength() - 1 );
929 else
930 aUrl += "/";
932 aIter = m_aContainer.find( aUrl );
935 if( aIter == m_aContainer.end() )
936 return;
938 auto aNPIter = std::find_if(aIter->second.begin(), aIter->second.end(),
939 [&aName](const NamePasswordRecord& rNPRecord) { return rNPRecord.GetUserName() == aName; });
941 if (aNPIter != aIter->second.end())
943 if( aNPIter->HasPasswords( PERSISTENT_RECORD ) && m_xStorageFile )
944 m_xStorageFile->remove( aURL, aName ); // remove record ( aURL, aName )
946 // the iterator will not be used any more so it can be removed directly
947 aIter->second.erase( aNPIter );
949 if( aIter->second.empty() )
950 m_aContainer.erase( aIter );
955 void SAL_CALL PasswordContainer::removePersistent( const OUString& aURL, const OUString& aName )
957 ::osl::MutexGuard aGuard( mMutex );
959 OUString aUrl( aURL );
960 if( m_aContainer.empty() )
961 return;
963 PasswordMap::iterator aIter = m_aContainer.find( aUrl );
965 if( aIter == m_aContainer.end() )
967 if( aUrl.endsWith("/") )
968 aUrl = aUrl.copy( 0, aUrl.getLength() - 1 );
969 else
970 aUrl += "/";
972 aIter = m_aContainer.find( aUrl );
975 if( aIter == m_aContainer.end() )
976 return;
978 auto aNPIter = std::find_if(aIter->second.begin(), aIter->second.end(),
979 [&aName](const NamePasswordRecord& rNPRecord) { return rNPRecord.GetUserName() == aName; });
981 if (aNPIter == aIter->second.end())
982 return;
984 if( aNPIter->HasPasswords( PERSISTENT_RECORD ) )
986 // TODO/LATER: should the password be converted to MemoryPassword?
987 aNPIter->RemovePasswords( PERSISTENT_RECORD );
989 if ( m_xStorageFile )
990 m_xStorageFile->remove( aURL, aName ); // remove record ( aURL, aName )
993 if( !aNPIter->HasPasswords( MEMORY_RECORD ) )
994 aIter->second.erase( aNPIter );
996 if( aIter->second.empty() )
997 m_aContainer.erase( aIter );
1000 void SAL_CALL PasswordContainer::removeAllPersistent()
1002 ::osl::MutexGuard aGuard( mMutex );
1004 if( m_xStorageFile )
1005 m_xStorageFile->clear();
1007 for( PasswordMap::iterator aIter = m_aContainer.begin(); aIter != m_aContainer.end(); )
1009 for( std::vector< NamePasswordRecord >::iterator aNPIter = aIter->second.begin(); aNPIter != aIter->second.end(); )
1011 if( aNPIter->HasPasswords( PERSISTENT_RECORD ) )
1013 // TODO/LATER: should the password be converted to MemoryPassword?
1014 aNPIter->RemovePasswords( PERSISTENT_RECORD );
1016 if ( m_xStorageFile )
1017 m_xStorageFile->remove( aIter->first, aNPIter->GetUserName() ); // remove record ( aURL, aName )
1020 if( !aNPIter->HasPasswords( MEMORY_RECORD ) )
1022 aNPIter = aIter->second.erase(aNPIter);
1024 else
1025 ++aNPIter;
1028 if( aIter->second.empty() )
1030 aIter = m_aContainer.erase(aIter);
1032 else
1033 ++aIter;
1037 Sequence< UrlRecord > SAL_CALL PasswordContainer::getAllPersistent( const Reference< XInteractionHandler >& xHandler )
1039 Sequence< UrlRecord > aResult;
1041 ::osl::MutexGuard aGuard( mMutex );
1042 for( const auto& rEntry : m_aContainer )
1044 Sequence< UserRecord > aUsers;
1045 for (auto const& aNP : rEntry.second)
1046 if( aNP.HasPasswords( PERSISTENT_RECORD ) )
1048 sal_Int32 oldLen = aUsers.getLength();
1049 aUsers.realloc( oldLen + 1 );
1050 aUsers.getArray()[ oldLen ] = UserRecord( aNP.GetUserName(), comphelper::containerToSequence( DecodePasswords( aNP.GetPersistentPasswords(), aNP.GetPersistentIV(),
1051 GetMasterPassword( xHandler ), css::task::PasswordRequestMode_PASSWORD_ENTER ) ) );
1054 if( aUsers.hasElements() )
1056 sal_Int32 oldLen = aResult.getLength();
1057 aResult.realloc( oldLen + 1 );
1058 aResult.getArray()[ oldLen ] = UrlRecord( rEntry.first, aUsers );
1062 return aResult;
1065 sal_Bool SAL_CALL PasswordContainer::authorizateWithMasterPassword( const uno::Reference< task::XInteractionHandler >& xHandler )
1067 bool bResult = false;
1068 OUString aEncodedMP, aEncodedMPIV;
1069 uno::Reference< task::XInteractionHandler > xTmpHandler = xHandler;
1070 ::osl::MutexGuard aGuard( mMutex );
1072 // the method should fail if there is no master password
1073 if( m_xStorageFile && m_xStorageFile->useStorage() && m_xStorageFile->getEncodedMasterPassword( aEncodedMP, aEncodedMPIV ) )
1075 if ( aEncodedMP.isEmpty() )
1077 // this is a default master password
1078 // no UI is necessary
1079 bResult = true;
1081 else
1083 if ( !xTmpHandler.is() )
1085 uno::Reference< lang::XMultiServiceFactory > xFactory( mComponent, uno::UNO_QUERY_THROW );
1086 uno::Reference< uno::XComponentContext > xContext( comphelper::getComponentContext(xFactory) );
1087 xTmpHandler.set( InteractionHandler::createWithParent(xContext, nullptr), uno::UNO_QUERY_THROW );
1090 if ( !m_aMasterPassword.isEmpty() )
1092 // there is a password, it should be just rechecked
1093 PasswordRequestMode aRMode = PasswordRequestMode_PASSWORD_ENTER;
1094 OUString aPass;
1096 do {
1097 aPass = RequestPasswordFromUser( aRMode, xTmpHandler );
1099 if (!aPass.isEmpty() && m_xStorageFile->getStorageVersion() == 0)
1101 aPass = ReencodeAsOldHash(aPass);
1104 bResult = ( !aPass.isEmpty() && aPass == m_aMasterPassword );
1105 aRMode = PasswordRequestMode_PASSWORD_REENTER; // further questions with error notification
1106 } while( !bResult && !aPass.isEmpty() );
1108 else
1112 // ask for the password, if user provide no correct password an exception will be thrown
1113 bResult = !GetMasterPassword( xTmpHandler ).isEmpty();
1115 catch( uno::Exception& )
1121 return bResult;
1124 sal_Bool SAL_CALL PasswordContainer::changeMasterPassword( const uno::Reference< task::XInteractionHandler >& xHandler )
1126 bool bResult = false;
1127 uno::Reference< task::XInteractionHandler > xTmpHandler = xHandler;
1128 ::osl::MutexGuard aGuard( mMutex );
1130 if ( m_xStorageFile && m_xStorageFile->useStorage() )
1132 if ( !xTmpHandler.is() )
1134 uno::Reference< lang::XMultiServiceFactory > xFactory( mComponent, uno::UNO_QUERY_THROW );
1135 uno::Reference< uno::XComponentContext > xContext( comphelper::getComponentContext(xFactory) );
1136 xTmpHandler.set( InteractionHandler::createWithParent(xContext, nullptr), uno::UNO_QUERY_THROW );
1139 bool bCanChangePassword = true;
1140 // if there is already a stored master password it should be entered by the user before the change happen
1141 OUString aEncodedMP, aEncodedMPIV;
1142 if( !m_aMasterPassword.isEmpty() || m_xStorageFile->getEncodedMasterPassword( aEncodedMP, aEncodedMPIV ) )
1143 bCanChangePassword = authorizateWithMasterPassword( xTmpHandler );
1145 if ( bCanChangePassword )
1147 // ask for the new password, but do not set it
1148 OUString aPass = RequestPasswordFromUser( PasswordRequestMode_PASSWORD_CREATE, xTmpHandler );
1150 if ( !aPass.isEmpty() )
1152 // get all the persistent entries if it is possible
1153 const Sequence< UrlRecord > aPersistent = getAllPersistent( uno::Reference< task::XInteractionHandler >() );
1155 // remove the master password and the entries persistence
1156 removeMasterPassword();
1158 // store the new master password
1159 m_aMasterPassword = aPass;
1160 std::vector< OUString > aMaster( 1, m_aMasterPassword );
1161 OUString aIV = createIV();
1162 m_xStorageFile->setEncodedMasterPassword(EncodePasswords(aMaster, aIV, m_aMasterPassword), aIV);
1164 // store all the entries with the new password
1165 for ( const auto& rURL : aPersistent )
1166 for ( const auto& rUser : rURL.UserList )
1167 addPersistent( rURL.Url, rUser.UserName, rUser.Passwords,
1168 uno::Reference< task::XInteractionHandler >() );
1170 bResult = true;
1175 return bResult;
1178 void SAL_CALL PasswordContainer::removeMasterPassword()
1180 // remove all the stored passwords and the master password
1181 removeAllPersistent();
1183 ::osl::MutexGuard aGuard( mMutex );
1184 if ( m_xStorageFile )
1186 m_aMasterPassword.clear();
1187 m_xStorageFile->setEncodedMasterPassword( OUString(), OUString() ); // let the master password be removed from configuration
1191 sal_Bool SAL_CALL PasswordContainer::hasMasterPassword( )
1193 ::osl::MutexGuard aGuard( mMutex );
1195 if ( !m_xStorageFile )
1196 throw uno::RuntimeException();
1198 OUString aEncodedMP, aEncodedMPIV;
1199 return ( m_xStorageFile->useStorage() && m_xStorageFile->getEncodedMasterPassword( aEncodedMP, aEncodedMPIV ) );
1202 sal_Bool SAL_CALL PasswordContainer::allowPersistentStoring( sal_Bool bAllow )
1204 ::osl::MutexGuard aGuard( mMutex );
1206 if ( !m_xStorageFile )
1207 throw uno::RuntimeException();
1209 if ( !bAllow )
1210 removeMasterPassword();
1212 if (m_xStorageFile->useStorage() == static_cast<bool>(bAllow))
1213 return bAllow;
1215 m_xStorageFile->setUseStorage( bAllow );
1216 return !bAllow;
1219 sal_Bool SAL_CALL PasswordContainer::isPersistentStoringAllowed()
1221 ::osl::MutexGuard aGuard( mMutex );
1223 if ( !m_xStorageFile )
1224 throw uno::RuntimeException();
1226 return m_xStorageFile->useStorage();
1229 sal_Bool SAL_CALL PasswordContainer::useDefaultMasterPassword( const uno::Reference< task::XInteractionHandler >& xHandler )
1231 bool bResult = false;
1232 uno::Reference< task::XInteractionHandler > xTmpHandler = xHandler;
1233 ::osl::MutexGuard aGuard( mMutex );
1235 if ( m_xStorageFile && m_xStorageFile->useStorage() )
1237 if ( !xTmpHandler.is() )
1239 uno::Reference< lang::XMultiServiceFactory > xFactory( mComponent, uno::UNO_QUERY_THROW );
1240 uno::Reference< uno::XComponentContext > xContext( comphelper::getComponentContext(xFactory) );
1241 xTmpHandler.set( InteractionHandler::createWithParent(xContext, nullptr), uno::UNO_QUERY_THROW );
1244 bool bCanChangePassword = true;
1245 // if there is already a stored nondefault master password it should be entered by the user before the change happen
1246 OUString aEncodedMP, aEncodedMPIV;
1247 if( m_xStorageFile->getEncodedMasterPassword( aEncodedMP, aEncodedMPIV ) && !aEncodedMP.isEmpty() )
1248 bCanChangePassword = authorizateWithMasterPassword( xTmpHandler );
1250 if ( bCanChangePassword )
1252 // generate the default password
1253 OUString aPass = GetDefaultMasterPassword();
1254 if ( !aPass.isEmpty() )
1256 // get all the persistent entries if it is possible
1257 const Sequence< UrlRecord > aPersistent = getAllPersistent( uno::Reference< task::XInteractionHandler >() );
1259 // remove the master password and the entries persistence
1260 removeMasterPassword();
1262 // store the empty string to flag the default master password
1263 m_aMasterPassword = aPass;
1264 m_xStorageFile->setEncodedMasterPassword( OUString(), OUString(), true );
1266 // store all the entries with the new password
1267 for ( const auto& rURL : aPersistent )
1268 for ( const auto& rUser : rURL.UserList )
1269 addPersistent( rURL.Url, rUser.UserName, rUser.Passwords,
1270 uno::Reference< task::XInteractionHandler >() );
1272 bResult = true;
1277 return bResult;
1281 sal_Bool SAL_CALL PasswordContainer::isDefaultMasterPasswordUsed()
1283 ::osl::MutexGuard aGuard( mMutex );
1285 if ( !m_xStorageFile )
1286 throw uno::RuntimeException();
1288 OUString aEncodedMP, aEncodedMPIV;
1289 return ( m_xStorageFile->useStorage() && m_xStorageFile->getEncodedMasterPassword( aEncodedMP, aEncodedMPIV ) && aEncodedMP.isEmpty() );
1293 void SAL_CALL PasswordContainer::addUrl( const OUString& Url, sal_Bool MakePersistent )
1295 mUrlContainer.add( Url, MakePersistent );
1298 OUString SAL_CALL PasswordContainer::findUrl( const OUString& Url )
1300 return mUrlContainer.find( Url );
1303 void SAL_CALL PasswordContainer::removeUrl( const OUString& Url )
1305 mUrlContainer.remove( Url );
1308 uno::Sequence< OUString > SAL_CALL PasswordContainer::getUrls( sal_Bool OnlyPersistent )
1310 return mUrlContainer.list( OnlyPersistent );
1314 void PasswordContainer::Notify()
1316 ::osl::MutexGuard aGuard( mMutex );
1318 // remove the cached persistent values in the memory
1319 for( auto& rEntry : m_aContainer )
1321 for( std::vector< NamePasswordRecord >::iterator aNPIter = rEntry.second.begin(); aNPIter != rEntry.second.end(); )
1323 if( aNPIter->HasPasswords( PERSISTENT_RECORD ) )
1325 aNPIter->RemovePasswords( PERSISTENT_RECORD );
1327 if ( m_xStorageFile )
1328 m_xStorageFile->remove( rEntry.first, aNPIter->GetUserName() ); // remove record ( aURL, aName )
1331 if( !aNPIter->HasPasswords( MEMORY_RECORD ) )
1333 aNPIter = rEntry.second.erase(aNPIter);
1335 else
1336 ++aNPIter;
1340 PasswordMap addon;
1341 if( m_xStorageFile )
1342 addon = m_xStorageFile->getInfo();
1344 for( const auto& rEntry : addon )
1346 PasswordMap::iterator aSearchIter = m_aContainer.find( rEntry.first );
1347 if( aSearchIter != m_aContainer.end() )
1348 for (auto const& aNP : rEntry.second)
1349 UpdateVector( aSearchIter->first, aSearchIter->second, aNP, false );
1350 else
1351 m_aContainer.insert( PairUrlRecord( rEntry.first, rEntry.second ) );
1355 OUString SAL_CALL PasswordContainer::getImplementationName( )
1357 return "stardiv.svl.PasswordContainer";
1360 sal_Bool SAL_CALL PasswordContainer::supportsService( const OUString& ServiceName )
1362 return cppu::supportsService( this, ServiceName );
1365 Sequence< OUString > SAL_CALL PasswordContainer::getSupportedServiceNames( )
1367 return { "com.sun.star.task.PasswordContainer" };
1370 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
1371 svl_PasswordContainer_get_implementation(
1372 css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&)
1374 return cppu::acquire(new PasswordContainer(context));
1378 MasterPasswordRequest_Impl::MasterPasswordRequest_Impl( PasswordRequestMode Mode )
1380 MasterPasswordRequest aRequest;
1382 aRequest.Classification = InteractionClassification_ERROR;
1383 aRequest.Mode = Mode;
1385 setRequest( makeAny( aRequest ) );
1387 // Fill continuations...
1388 Sequence< RememberAuthentication > aRememberModes{ RememberAuthentication_NO };
1390 m_xAuthSupplier
1391 = new ::ucbhelper::InteractionSupplyAuthentication(
1392 this,
1393 false, // bCanSetRealm
1394 false, // bCanSetUserName
1395 true, // bCanSetPassword
1396 false, // bCanSetAccount
1397 aRememberModes, // rRememberPasswordModes
1398 RememberAuthentication_NO, // eDefaultRememberPasswordMode
1399 aRememberModes, // rRememberAccountModes
1400 RememberAuthentication_NO, // eDefaultRememberAccountMode
1401 false // bCanUseSystemCredentials
1404 Sequence<
1405 Reference< XInteractionContinuation > > aContinuations{
1406 new ::ucbhelper::InteractionAbort( this ),
1407 new ::ucbhelper::InteractionRetry( this ),
1408 m_xAuthSupplier
1411 setContinuations( aContinuations );
1416 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */