726 lines
22 KiB
C++
726 lines
22 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <tabprotection.hxx>
|
|
#include <svl/PasswordHelper.hxx>
|
|
#include <comphelper/docpasswordhelper.hxx>
|
|
#include <comphelper/hash.hxx>
|
|
#include <comphelper/sequence.hxx>
|
|
#include <osl/diagnose.h>
|
|
#include <document.hxx>
|
|
|
|
#include <vector>
|
|
|
|
#define DEBUG_TAB_PROTECTION 0
|
|
|
|
constexpr OUString URI_SHA1 = u"http://www.w3.org/2000/09/xmldsig#sha1"_ustr;
|
|
constexpr OUString URI_SHA256_ODF12 = u"http://www.w3.org/2000/09/xmldsig#sha256"_ustr;
|
|
constexpr OUStringLiteral URI_SHA256_W3C = u"http://www.w3.org/2001/04/xmlenc#sha256";
|
|
constexpr OUString URI_XLS_LEGACY = u"http://docs.oasis-open.org/office/ns/table/legacy-hash-excel"_ustr;
|
|
|
|
using namespace ::com::sun::star;
|
|
using ::com::sun::star::uno::Sequence;
|
|
using ::std::vector;
|
|
|
|
bool ScPassHashHelper::needsPassHashRegen(const ScDocument& rDoc, ScPasswordHash eHash1, ScPasswordHash eHash2)
|
|
{
|
|
if (rDoc.IsDocProtected())
|
|
{
|
|
const ScDocProtection* p = rDoc.GetDocProtection();
|
|
if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash1, eHash2))
|
|
return true;
|
|
}
|
|
|
|
SCTAB nTabCount = rDoc.GetTableCount();
|
|
for (SCTAB i = 0; i < nTabCount; ++i)
|
|
{
|
|
const ScTableProtection* p = rDoc.GetTabProtection(i);
|
|
if (!p || !p->isProtected())
|
|
// Sheet not protected. Skip it.
|
|
continue;
|
|
|
|
if (!p->isPasswordEmpty() && !p->hasPasswordHash(eHash1, eHash2))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
const OUString & ScPassHashHelper::getHashURI(ScPasswordHash eHash)
|
|
{
|
|
switch (eHash)
|
|
{
|
|
case PASSHASH_SHA256:
|
|
return URI_SHA256_ODF12;
|
|
case PASSHASH_SHA1:
|
|
return URI_SHA1;
|
|
case PASSHASH_XL:
|
|
return URI_XLS_LEGACY;
|
|
case PASSHASH_UNSPECIFIED:
|
|
default:
|
|
;
|
|
}
|
|
return EMPTY_OUSTRING;
|
|
}
|
|
|
|
ScPasswordHash ScPassHashHelper::getHashTypeFromURI(std::u16string_view rURI)
|
|
{
|
|
if (rURI == URI_SHA256_ODF12 || rURI == URI_SHA256_W3C)
|
|
return PASSHASH_SHA256;
|
|
if ( rURI == URI_SHA1 )
|
|
return PASSHASH_SHA1;
|
|
else if ( rURI == URI_XLS_LEGACY )
|
|
return PASSHASH_XL;
|
|
return PASSHASH_UNSPECIFIED;
|
|
}
|
|
|
|
bool ScOoxPasswordHash::verifyPassword( const OUString& aPassText ) const
|
|
{
|
|
if (!hasPassword())
|
|
return false;
|
|
|
|
const OUString aHash( comphelper::DocPasswordHelper::GetOoxHashAsBase64(
|
|
aPassText, maSaltValue, mnSpinCount, comphelper::Hash::IterCount::APPEND, maAlgorithmName));
|
|
if (aHash.isEmpty())
|
|
// unsupported algorithm
|
|
return false;
|
|
|
|
return aHash == maHashValue;
|
|
}
|
|
|
|
ScPassHashProtectable::~ScPassHashProtectable()
|
|
{
|
|
}
|
|
|
|
class ScTableProtectionImpl
|
|
{
|
|
public:
|
|
static Sequence<sal_Int8> hashPassword(std::u16string_view aPassText, ScPasswordHash eHash);
|
|
static Sequence<sal_Int8> hashPassword(const Sequence<sal_Int8>& rPassHash, ScPasswordHash eHash);
|
|
|
|
explicit ScTableProtectionImpl(SCSIZE nOptSize);
|
|
explicit ScTableProtectionImpl(const ScTableProtectionImpl& r);
|
|
|
|
bool isProtected() const { return mbProtected;}
|
|
bool isProtectedWithPass() const;
|
|
void setProtected(bool bProtected);
|
|
|
|
bool isPasswordEmpty() const { return mbEmptyPass;}
|
|
bool hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const;
|
|
void setPassword(const OUString& aPassText);
|
|
css::uno::Sequence<sal_Int8> getPasswordHash(
|
|
ScPasswordHash eHash, ScPasswordHash eHash2) const;
|
|
const ScOoxPasswordHash& getPasswordHash() const;
|
|
void setPasswordHash(
|
|
const css::uno::Sequence<sal_Int8>& aPassword,
|
|
ScPasswordHash eHash, ScPasswordHash eHash2);
|
|
void setPasswordHash( const OUString& rAlgorithmName, const OUString& rHashValue,
|
|
const OUString& rSaltValue, sal_uInt32 nSpinCount );
|
|
bool verifyPassword(const OUString& aPassText) const;
|
|
|
|
bool isOptionEnabled(SCSIZE nOptId) const;
|
|
void setOption(SCSIZE nOptId, bool bEnabled);
|
|
|
|
void setEnhancedProtection( ::std::vector< ScEnhancedProtection > && rProt );
|
|
const ::std::vector< ScEnhancedProtection > & getEnhancedProtection() const { return maEnhancedProtection;}
|
|
bool updateReference( UpdateRefMode, const ScDocument&, const ScRange& rWhere, SCCOL nDx, SCROW nDy, SCTAB nDz );
|
|
bool isBlockEditable( const ScRange& rRange ) const;
|
|
bool isSelectionEditable( const ScRangeList& rRangeList ) const;
|
|
|
|
private:
|
|
OUString maPassText;
|
|
css::uno::Sequence<sal_Int8> maPassHash;
|
|
::std::vector<bool> maOptions;
|
|
bool mbEmptyPass;
|
|
bool mbProtected;
|
|
ScPasswordHash meHash1;
|
|
ScPasswordHash meHash2;
|
|
ScOoxPasswordHash maPasswordHash;
|
|
::std::vector< ScEnhancedProtection > maEnhancedProtection;
|
|
};
|
|
|
|
Sequence<sal_Int8> ScTableProtectionImpl::hashPassword(std::u16string_view aPassText, ScPasswordHash eHash)
|
|
{
|
|
Sequence<sal_Int8> aHash;
|
|
switch (eHash)
|
|
{
|
|
case PASSHASH_XL:
|
|
aHash = ::comphelper::DocPasswordHelper::GetXLHashAsSequence( aPassText );
|
|
break;
|
|
case PASSHASH_SHA1:
|
|
SvPasswordHelper::GetHashPassword(aHash, aPassText);
|
|
break;
|
|
case PASSHASH_SHA1_UTF8:
|
|
SvPasswordHelper::GetHashPasswordSHA1UTF8(aHash, aPassText);
|
|
break;
|
|
case PASSHASH_SHA256:
|
|
SvPasswordHelper::GetHashPasswordSHA256(aHash, aPassText);
|
|
break;
|
|
default:
|
|
;
|
|
}
|
|
return aHash;
|
|
}
|
|
|
|
Sequence<sal_Int8> ScTableProtectionImpl::hashPassword(
|
|
const Sequence<sal_Int8>& rPassHash, ScPasswordHash eHash)
|
|
{
|
|
if (!rPassHash.hasElements() || eHash == PASSHASH_UNSPECIFIED)
|
|
return rPassHash;
|
|
|
|
// TODO: Right now, we only support double-hash by SHA1.
|
|
if (eHash == PASSHASH_SHA1)
|
|
{
|
|
auto aChars = comphelper::sequenceToContainer<vector<char>>(rPassHash);
|
|
|
|
Sequence<sal_Int8> aNewHash;
|
|
SvPasswordHelper::GetHashPassword(aNewHash, aChars.data(), aChars.size());
|
|
return aNewHash;
|
|
}
|
|
|
|
return rPassHash;
|
|
}
|
|
|
|
ScTableProtectionImpl::ScTableProtectionImpl(SCSIZE nOptSize) :
|
|
maOptions(nOptSize),
|
|
mbEmptyPass(true),
|
|
mbProtected(false),
|
|
meHash1(PASSHASH_SHA1),
|
|
meHash2(PASSHASH_UNSPECIFIED)
|
|
{
|
|
}
|
|
|
|
ScTableProtectionImpl::ScTableProtectionImpl(const ScTableProtectionImpl& r) :
|
|
maPassText(r.maPassText),
|
|
maPassHash(r.maPassHash),
|
|
maOptions(r.maOptions),
|
|
mbEmptyPass(r.mbEmptyPass),
|
|
mbProtected(r.mbProtected),
|
|
meHash1(r.meHash1),
|
|
meHash2(r.meHash2),
|
|
maPasswordHash(r.maPasswordHash),
|
|
maEnhancedProtection(r.maEnhancedProtection)
|
|
{
|
|
}
|
|
|
|
bool ScTableProtectionImpl::isProtectedWithPass() const
|
|
{
|
|
if (!mbProtected)
|
|
return false;
|
|
|
|
return !maPassText.isEmpty() || maPassHash.hasElements() || maPasswordHash.hasPassword();
|
|
}
|
|
|
|
void ScTableProtectionImpl::setProtected(bool bProtected)
|
|
{
|
|
mbProtected = bProtected;
|
|
// We need to keep the old password even when the protection is off. So,
|
|
// don't erase the password data here.
|
|
}
|
|
|
|
void ScTableProtectionImpl::setPassword(const OUString& aPassText)
|
|
{
|
|
// We can't hash it here because we don't know whether this document will
|
|
// get saved to Excel or ODF, depending on which we will need to use a
|
|
// different hashing algorithm. One alternative is to hash it using all
|
|
// hash algorithms that we support, and store them all.
|
|
|
|
maPassText = aPassText;
|
|
mbEmptyPass = aPassText.isEmpty();
|
|
if (mbEmptyPass)
|
|
{
|
|
maPassHash = Sequence<sal_Int8>();
|
|
}
|
|
maPasswordHash.clear();
|
|
}
|
|
|
|
bool ScTableProtectionImpl::hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
|
|
{
|
|
if (mbEmptyPass)
|
|
return true;
|
|
|
|
if (!maPassText.isEmpty())
|
|
return true;
|
|
|
|
if (meHash1 == eHash)
|
|
{
|
|
if (meHash2 == PASSHASH_UNSPECIFIED)
|
|
// single hash.
|
|
return true;
|
|
|
|
return meHash2 == eHash2;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
Sequence<sal_Int8> ScTableProtectionImpl::getPasswordHash(
|
|
ScPasswordHash eHash, ScPasswordHash eHash2) const
|
|
{
|
|
Sequence<sal_Int8> aPassHash;
|
|
|
|
if (mbEmptyPass)
|
|
// Flagged as empty.
|
|
return aPassHash;
|
|
|
|
if (!maPassText.isEmpty())
|
|
{
|
|
// Cleartext password exists. Hash it.
|
|
aPassHash = hashPassword(maPassText, eHash);
|
|
if (eHash2 != PASSHASH_UNSPECIFIED)
|
|
// Double-hash it.
|
|
aPassHash = hashPassword(aPassHash, eHash2);
|
|
|
|
return aPassHash;
|
|
}
|
|
else
|
|
{
|
|
// No clear text password. Check if we have a hash value of the right hash type.
|
|
if (meHash1 == eHash)
|
|
{
|
|
aPassHash = maPassHash;
|
|
|
|
if (meHash2 == eHash2)
|
|
// Matching double-hash requested.
|
|
return aPassHash;
|
|
else if (meHash2 == PASSHASH_UNSPECIFIED)
|
|
// primary hashing type match. Double hash it by the requested
|
|
// double-hash type.
|
|
return hashPassword(aPassHash, eHash2);
|
|
}
|
|
}
|
|
|
|
// failed.
|
|
return Sequence<sal_Int8>();
|
|
}
|
|
|
|
const ScOoxPasswordHash& ScTableProtectionImpl::getPasswordHash() const
|
|
{
|
|
return maPasswordHash;
|
|
}
|
|
|
|
void ScTableProtectionImpl::setPasswordHash(
|
|
const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash, ScPasswordHash eHash2)
|
|
{
|
|
sal_Int32 nLen = aPassword.getLength();
|
|
mbEmptyPass = nLen <= 0;
|
|
meHash1 = eHash;
|
|
meHash2 = eHash2;
|
|
maPassHash = aPassword;
|
|
|
|
#if DEBUG_TAB_PROTECTION
|
|
for (sal_Int8 n : aPassword)
|
|
printf("%2.2X ", static_cast<sal_uInt8>(n));
|
|
printf("\n");
|
|
#endif
|
|
}
|
|
|
|
void ScTableProtectionImpl::setPasswordHash( const OUString& rAlgorithmName, const OUString& rHashValue,
|
|
const OUString& rSaltValue, sal_uInt32 nSpinCount )
|
|
{
|
|
if (!rHashValue.isEmpty())
|
|
{
|
|
// Invalidate the other hashes.
|
|
setPasswordHash( uno::Sequence<sal_Int8>(), PASSHASH_UNSPECIFIED, PASSHASH_UNSPECIFIED);
|
|
|
|
// We don't know whether this is an empty password (or would
|
|
// unnecessarily have to try to verify an empty password), assume it is
|
|
// not. A later verifyPassword() with an empty password will determine.
|
|
// If this was not set to false then a verifyPassword() with an empty
|
|
// password would unlock even if this hash here wasn't for an empty
|
|
// password. Ugly stuff.
|
|
mbEmptyPass = false;
|
|
}
|
|
|
|
maPasswordHash.maAlgorithmName = rAlgorithmName;
|
|
maPasswordHash.maHashValue = rHashValue;
|
|
maPasswordHash.maSaltValue = rSaltValue;
|
|
maPasswordHash.mnSpinCount = nSpinCount;
|
|
}
|
|
|
|
bool ScTableProtectionImpl::verifyPassword(const OUString& aPassText) const
|
|
{
|
|
#if DEBUG_TAB_PROTECTION
|
|
fprintf(stdout, "ScTableProtectionImpl::verifyPassword: input = '%s'\n",
|
|
OUStringToOString(aPassText, RTL_TEXTENCODING_UTF8).getStr());
|
|
#endif
|
|
|
|
if (mbEmptyPass)
|
|
return aPassText.isEmpty();
|
|
|
|
if (!maPassText.isEmpty())
|
|
// Clear text password exists, and this one takes precedence.
|
|
return aPassText == maPassText;
|
|
|
|
// For PASSHASH_UNSPECIFIED also maPassHash is empty and any aPassText
|
|
// would yield an empty hash as well and thus compare true. Don't.
|
|
if (meHash1 != PASSHASH_UNSPECIFIED)
|
|
{
|
|
Sequence<sal_Int8> aHash = hashPassword(aPassText, meHash1);
|
|
aHash = hashPassword(aHash, meHash2);
|
|
|
|
#if DEBUG_TAB_PROTECTION
|
|
fprintf(stdout, "ScTableProtectionImpl::verifyPassword: hash = ");
|
|
for (sal_Int32 i = 0; i < aHash.getLength(); ++i)
|
|
printf("%2.2X ", static_cast<sal_uInt8>(aHash[i]));
|
|
printf("\n");
|
|
#endif
|
|
|
|
if (aHash == maPassHash)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// tdf#115483 compat hack for ODF 1.2; for now UTF8-SHA1 passwords are only
|
|
// verified, not generated
|
|
if (meHash1 == PASSHASH_SHA1 && meHash2 == PASSHASH_UNSPECIFIED)
|
|
{
|
|
Sequence<sal_Int8> const aHash2 = hashPassword(aPassText, PASSHASH_SHA1_UTF8);
|
|
return aHash2 == maPassHash;
|
|
}
|
|
|
|
// Not yet generated or tracked with meHash1 or meHash2, but can be read
|
|
// from OOXML.
|
|
return maPasswordHash.verifyPassword( aPassText);
|
|
}
|
|
|
|
bool ScTableProtectionImpl::isOptionEnabled(SCSIZE nOptId) const
|
|
{
|
|
if ( maOptions.size() <= static_cast<size_t>(nOptId) )
|
|
{
|
|
OSL_FAIL("ScTableProtectionImpl::isOptionEnabled: wrong size");
|
|
return false;
|
|
}
|
|
|
|
return maOptions[nOptId];
|
|
}
|
|
|
|
void ScTableProtectionImpl::setOption(SCSIZE nOptId, bool bEnabled)
|
|
{
|
|
if ( maOptions.size() <= static_cast<size_t>(nOptId) )
|
|
{
|
|
OSL_FAIL("ScTableProtectionImpl::setOption: wrong size");
|
|
return;
|
|
}
|
|
|
|
maOptions[nOptId] = bEnabled;
|
|
}
|
|
|
|
void ScTableProtectionImpl::setEnhancedProtection( ::std::vector< ScEnhancedProtection > && rProt )
|
|
{
|
|
maEnhancedProtection = std::move(rProt);
|
|
}
|
|
|
|
bool ScTableProtectionImpl::updateReference( UpdateRefMode eMode, const ScDocument& rDoc,
|
|
const ScRange& rWhere, SCCOL nDx, SCROW nDy, SCTAB nDz )
|
|
{
|
|
bool bChanged = false;
|
|
for (auto& rEnhancedProtection : maEnhancedProtection)
|
|
{
|
|
if (rEnhancedProtection.maRangeList.is())
|
|
bChanged |= rEnhancedProtection.maRangeList->UpdateReference( eMode, &rDoc, rWhere, nDx, nDy, nDz);
|
|
}
|
|
return bChanged;
|
|
}
|
|
|
|
bool ScTableProtectionImpl::isBlockEditable( const ScRange& rRange ) const
|
|
{
|
|
/* TODO: ask for password (and remember) if a password was set for
|
|
* a matching range and no matching range without password was encountered.
|
|
* Would need another return type than boolean to reflect
|
|
* "password required for a specific protection". */
|
|
|
|
// No protection exception or overriding permission to edit if empty.
|
|
if (maEnhancedProtection.empty())
|
|
return false;
|
|
|
|
// No security descriptor in an enhanced protection means the ranges of
|
|
// that protection are editable. If there is any security descriptor
|
|
// present we assume the permission to edit is not granted. Until we
|
|
// actually can evaluate the descriptors...
|
|
|
|
{
|
|
auto lIsEditable = [rRange](const ScEnhancedProtection& rEnhancedProtection) {
|
|
return !rEnhancedProtection.hasSecurityDescriptor()
|
|
&& rEnhancedProtection.maRangeList.is() && rEnhancedProtection.maRangeList->Contains( rRange)
|
|
&& !rEnhancedProtection.hasPassword(); // Range is editable if no password is assigned.
|
|
};
|
|
if (std::any_of(maEnhancedProtection.begin(), maEnhancedProtection.end(), std::move(lIsEditable)))
|
|
return true;
|
|
}
|
|
|
|
// For a single address, a simple check with single ranges was sufficient.
|
|
if (rRange.aStart == rRange.aEnd)
|
|
return false;
|
|
|
|
// Test also for cases where rRange is encompassed by a union of two or
|
|
// more ranges of the list. The original ranges are not necessarily joined.
|
|
for (const auto& rEnhancedProtection : maEnhancedProtection)
|
|
{
|
|
if (!rEnhancedProtection.hasSecurityDescriptor() && rEnhancedProtection.maRangeList.is())
|
|
{
|
|
ScRangeList aList( rEnhancedProtection.maRangeList->GetIntersectedRange( rRange));
|
|
if (aList.size() == 1 && aList[0] == rRange)
|
|
{
|
|
// Range is editable if no password is assigned.
|
|
if (!rEnhancedProtection.hasPassword())
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ranges may even be distributed over different protection records, for
|
|
// example if they are assigned different names, and can have different
|
|
// passwords. Combine the ones that can be edited.
|
|
/* TODO: once we handle passwords, remember a successful unlock at
|
|
* ScEnhancedProtection so we can use that here. */
|
|
ScRangeList aRangeList;
|
|
for (const auto& rEnhancedProtection : maEnhancedProtection)
|
|
{
|
|
if (!rEnhancedProtection.hasSecurityDescriptor() && rEnhancedProtection.maRangeList.is())
|
|
{
|
|
// Ranges are editable if no password is assigned.
|
|
if (!rEnhancedProtection.hasPassword())
|
|
{
|
|
const ScRangeList& rRanges = *rEnhancedProtection.maRangeList;
|
|
size_t nRanges = rRanges.size();
|
|
for (size_t i=0; i < nRanges; ++i)
|
|
{
|
|
aRangeList.push_back( rRanges[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ScRangeList aResultList( aRangeList.GetIntersectedRange( rRange));
|
|
return aResultList.size() == 1 && aResultList[0] == rRange;
|
|
}
|
|
|
|
bool ScTableProtectionImpl::isSelectionEditable( const ScRangeList& rRangeList ) const
|
|
{
|
|
if (rRangeList.empty())
|
|
return false;
|
|
|
|
for (size_t i=0, nRanges = rRangeList.size(); i < nRanges; ++i)
|
|
{
|
|
if (!isBlockEditable( rRangeList[i]))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
ScDocProtection::ScDocProtection() :
|
|
mpImpl(new ScTableProtectionImpl(static_cast<SCSIZE>(ScDocProtection::NONE)))
|
|
{
|
|
}
|
|
|
|
ScDocProtection::ScDocProtection(const ScDocProtection& r) :
|
|
ScPassHashProtectable(),
|
|
mpImpl(new ScTableProtectionImpl(*r.mpImpl))
|
|
{
|
|
}
|
|
|
|
ScDocProtection::~ScDocProtection()
|
|
{
|
|
}
|
|
|
|
bool ScDocProtection::isProtected() const
|
|
{
|
|
return mpImpl->isProtected();
|
|
}
|
|
|
|
bool ScDocProtection::isProtectedWithPass() const
|
|
{
|
|
return mpImpl->isProtectedWithPass();
|
|
}
|
|
|
|
void ScDocProtection::setProtected(bool bProtected)
|
|
{
|
|
mpImpl->setProtected(bProtected);
|
|
|
|
// Currently Calc doesn't support document protection options. So, let's
|
|
// assume that when the document is protected, its structure is protected.
|
|
// We need to do this for Excel export.
|
|
mpImpl->setOption(ScDocProtection::STRUCTURE, bProtected);
|
|
}
|
|
|
|
bool ScDocProtection::isPasswordEmpty() const
|
|
{
|
|
return mpImpl->isPasswordEmpty();
|
|
}
|
|
|
|
bool ScDocProtection::hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
|
|
{
|
|
return mpImpl->hasPasswordHash(eHash, eHash2);
|
|
}
|
|
|
|
void ScDocProtection::setPassword(const OUString& aPassText)
|
|
{
|
|
mpImpl->setPassword(aPassText);
|
|
}
|
|
|
|
uno::Sequence<sal_Int8> ScDocProtection::getPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
|
|
{
|
|
return mpImpl->getPasswordHash(eHash, eHash2);
|
|
}
|
|
|
|
const ScOoxPasswordHash& ScDocProtection::getPasswordHash() const
|
|
{
|
|
return mpImpl->getPasswordHash();
|
|
}
|
|
|
|
void ScDocProtection::setPasswordHash(
|
|
const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash, ScPasswordHash eHash2)
|
|
{
|
|
mpImpl->setPasswordHash(aPassword, eHash, eHash2);
|
|
}
|
|
|
|
void ScDocProtection::setPasswordHash( const OUString& rAlgorithmName, const OUString& rHashValue,
|
|
const OUString& rSaltValue, sal_uInt32 nSpinCount )
|
|
{
|
|
mpImpl->setPasswordHash( rAlgorithmName, rHashValue, rSaltValue, nSpinCount);
|
|
}
|
|
|
|
bool ScDocProtection::verifyPassword(const OUString& aPassText) const
|
|
{
|
|
return mpImpl->verifyPassword(aPassText);
|
|
}
|
|
|
|
bool ScDocProtection::isOptionEnabled(Option eOption) const
|
|
{
|
|
return mpImpl->isOptionEnabled(eOption);
|
|
}
|
|
|
|
void ScDocProtection::setOption(Option eOption, bool bEnabled)
|
|
{
|
|
mpImpl->setOption(eOption, bEnabled);
|
|
}
|
|
|
|
ScTableProtection::ScTableProtection() :
|
|
mpImpl(new ScTableProtectionImpl(static_cast<SCSIZE>(ScTableProtection::NONE)))
|
|
{
|
|
// Set default values for the options.
|
|
mpImpl->setOption(SELECT_LOCKED_CELLS, true);
|
|
mpImpl->setOption(SELECT_UNLOCKED_CELLS, true);
|
|
}
|
|
|
|
ScTableProtection::ScTableProtection(const ScTableProtection& r) :
|
|
ScPassHashProtectable(),
|
|
mpImpl(new ScTableProtectionImpl(*r.mpImpl))
|
|
{
|
|
}
|
|
|
|
ScTableProtection::~ScTableProtection()
|
|
{
|
|
}
|
|
|
|
bool ScTableProtection::isProtected() const
|
|
{
|
|
return mpImpl->isProtected();
|
|
}
|
|
|
|
bool ScTableProtection::isProtectedWithPass() const
|
|
{
|
|
return mpImpl->isProtectedWithPass();
|
|
}
|
|
|
|
void ScTableProtection::setProtected(bool bProtected)
|
|
{
|
|
mpImpl->setProtected(bProtected);
|
|
}
|
|
|
|
bool ScTableProtection::isPasswordEmpty() const
|
|
{
|
|
return mpImpl->isPasswordEmpty();
|
|
}
|
|
|
|
bool ScTableProtection::hasPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
|
|
{
|
|
return mpImpl->hasPasswordHash(eHash, eHash2);
|
|
}
|
|
|
|
void ScTableProtection::setPassword(const OUString& aPassText)
|
|
{
|
|
mpImpl->setPassword(aPassText);
|
|
}
|
|
|
|
Sequence<sal_Int8> ScTableProtection::getPasswordHash(ScPasswordHash eHash, ScPasswordHash eHash2) const
|
|
{
|
|
return mpImpl->getPasswordHash(eHash, eHash2);
|
|
}
|
|
|
|
const ScOoxPasswordHash& ScTableProtection::getPasswordHash() const
|
|
{
|
|
return mpImpl->getPasswordHash();
|
|
}
|
|
|
|
void ScTableProtection::setPasswordHash(
|
|
const uno::Sequence<sal_Int8>& aPassword, ScPasswordHash eHash, ScPasswordHash eHash2)
|
|
{
|
|
mpImpl->setPasswordHash(aPassword, eHash, eHash2);
|
|
}
|
|
|
|
void ScTableProtection::setPasswordHash( const OUString& rAlgorithmName, const OUString& rHashValue,
|
|
const OUString& rSaltValue, sal_uInt32 nSpinCount )
|
|
{
|
|
mpImpl->setPasswordHash( rAlgorithmName, rHashValue, rSaltValue, nSpinCount);
|
|
}
|
|
|
|
bool ScTableProtection::verifyPassword(const OUString& aPassText) const
|
|
{
|
|
return mpImpl->verifyPassword(aPassText);
|
|
}
|
|
|
|
bool ScTableProtection::isOptionEnabled(Option eOption) const
|
|
{
|
|
return mpImpl->isOptionEnabled(eOption);
|
|
}
|
|
|
|
void ScTableProtection::setOption(Option eOption, bool bEnabled)
|
|
{
|
|
mpImpl->setOption(eOption, bEnabled);
|
|
}
|
|
|
|
void ScTableProtection::setEnhancedProtection( ::std::vector< ScEnhancedProtection > && rProt )
|
|
{
|
|
mpImpl->setEnhancedProtection(std::move(rProt));
|
|
}
|
|
|
|
const ::std::vector< ScEnhancedProtection > & ScTableProtection::getEnhancedProtection() const
|
|
{
|
|
return mpImpl->getEnhancedProtection();
|
|
}
|
|
|
|
bool ScTableProtection::updateReference( UpdateRefMode eMode, const ScDocument& rDoc, const ScRange& rWhere,
|
|
SCCOL nDx, SCROW nDy, SCTAB nDz )
|
|
{
|
|
return mpImpl->updateReference( eMode, rDoc, rWhere, nDx, nDy, nDz);
|
|
}
|
|
|
|
bool ScTableProtection::isBlockEditable( const ScRange& rRange ) const
|
|
{
|
|
return mpImpl->isBlockEditable( rRange);
|
|
}
|
|
|
|
bool ScTableProtection::isSelectionEditable( const ScRangeList& rRangeList ) const
|
|
{
|
|
return mpImpl->isSelectionEditable( rRangeList);
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|