tdf#155665 Adding option to remember signatures for each save
Added the option in digital signatures dialog to remember used
signature.
Implemented ResignDocument function in objserv.cxx to resign after
every save in case the option to remember signature is on.
Added a new dialog box that checks whether there is a need to
remember the signature.
Change-Id: Ia7dbcc952044e9542e3fe6cd84b5d6633fcd1461
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152687
Reviewed-by: Heiko Tietze <heiko.tietze@documentfoundation.org>
Reviewed-by: Thorsten Behrens <thorsten.behrens@allotropia.de>
Tested-by: Thorsten Behrens <thorsten.behrens@allotropia.de>
diff --git a/include/sfx2/objsh.hxx b/include/sfx2/objsh.hxx
index b29fb43..15533c2 100644
--- a/include/sfx2/objsh.hxx
+++ b/include/sfx2/objsh.hxx
@@ -190,6 +190,7 @@ private:
// sal_False := new object
bool bIsInGenerateThumbnail; //optimize thumbnail generate and store procedure to improve odt saving performance, i120030
bool mbAvoidRecentDocs; ///< Avoid adding to the recent documents list, if not necessary.
bool bRememberSignature; // Do we want to remember the signature.
enum TriState {undefined, yes, no};
TriState mbContinueImportOnFilterExceptions = undefined; // try to import as much as possible
@@ -199,6 +200,8 @@ private:
SAL_DLLPRIVATE void UpdateTime_Impl(const css::uno::Reference<
css::document::XDocumentProperties> & i_xDocProps);
css::uno::Sequence< css::security::DocumentSignatureInformation > rSignatureInfosRemembered;
SAL_DLLPRIVATE bool SaveTo_Impl(SfxMedium &rMedium, const SfxItemSet* pSet );
protected:
@@ -350,13 +353,14 @@ public:
void AfterSigning(bool bSignSuccess, bool bSignScriptingContent);
bool HasValidSignatures() const;
SignatureState GetDocumentSignatureState();
void SignDocumentContent(weld::Window* pDialogParent);
bool SignDocumentContent(weld::Window* pDialogParent);
css::uno::Sequence<css::security::DocumentSignatureInformation> GetDocumentSignatureInformation(
bool bScriptingContent,
const css::uno::Reference<css::security::XDocumentDigitalSignatures>& xSigner
= css::uno::Reference<css::security::XDocumentDigitalSignatures>());
bool SignDocumentContentUsingCertificate(const css::uno::Reference<css::security::XCertificate>& xCertificate);
bool ResignDocument(css::uno::Sequence< css::security::DocumentSignatureInformation >& rSignaturesInfo);
void SignSignatureLine(weld::Window* pDialogParent, const OUString& aSignatureLineId,
const css::uno::Reference<css::security::XCertificate>& xCert,
@@ -364,7 +368,7 @@ public:
const css::uno::Reference<css::graphic::XGraphic>& xInvalidGraphic,
const OUString& aComment);
SignatureState GetScriptingSignatureState();
void SignScriptingContent(weld::Window* pDialogParent);
bool SignScriptingContent(weld::Window* pDialogParent);
DECL_DLLPRIVATE_LINK(SignDocumentHandler, weld::Button&, void);
virtual std::shared_ptr<SfxDocumentInfoDialog> CreateDocumentInfoDialog(weld::Window* pParent, const SfxItemSet& rItemSet);
@@ -458,6 +462,8 @@ public:
/// Don't add to the recent documents - it's an expensive operation, sometimes it is not wanted.
bool IsAvoidRecentDocs() const { return mbAvoidRecentDocs; }
bool IsRememberingSignature() const { return bRememberSignature; }
/// Don't add to the recent documents - it's an expensive operation, sometimes it is not wanted.
void AvoidRecentDocs(bool bAvoid) { mbAvoidRecentDocs = bAvoid; }
diff --git a/include/sfx2/strings.hrc b/include/sfx2/strings.hrc
index bd2c0b5..3ccc50c 100644
--- a/include/sfx2/strings.hrc
+++ b/include/sfx2/strings.hrc
@@ -149,6 +149,7 @@
#define RID_SVXSTR_XMLSEC_QUERY_LOSINGSIGNATURE NC_("RID_SVXSTR_XMLSEC_QUERY_LOSINGSIGNATURE", "Saving will remove all existing signatures.\nDo you want to continue saving the document?")
#define RID_SVXSTR_XMLSEC_QUERY_SAVEBEFORESIGN NC_("RID_SVXSTR_XMLSEC_QUERY_SAVEBEFORESIGN", "The document has to be saved before it can be signed.\nDo you want to save the document?")
#define STR_QUERY_CANCELCHECKOUT NC_("STR_QUERY_CANCELCHECKOUT", "This will discard all changes on the server since check-out.\nDo you want to proceed?")
#define STR_QUERY_REMEMBERSIGNATURE NC_("STR_QUERY_REMEMBERSIGNATURE", "Do you want to remember that signature for each save?")
#define STR_INFO_WRONGDOCFORMAT NC_("STR_INFO_WRONGDOCFORMAT", "This document must be saved in OpenDocument file format before it can be digitally signed.")
#define RID_XMLSEC_DOCUMENTSIGNED NC_("RID_XMLSEC_DOCUMENTSIGNED", " (Signed)")
#define STR_EMBEDDED_TITLE NC_("STR_EMBEDDED_TITLE", " (Embedded document)")
diff --git a/sfx2/source/doc/guisaveas.cxx b/sfx2/source/doc/guisaveas.cxx
index b6d4ce6..272d68f 100644
--- a/sfx2/source/doc/guisaveas.cxx
+++ b/sfx2/source/doc/guisaveas.cxx
@@ -1487,11 +1487,14 @@ bool SfxStoringHelper::GUIStoreModel( const uno::Reference< frame::XModel >& xMo
if (!comphelper::LibreOfficeKit::isActive() && !( m_nStoreMode & EXPORT_REQUESTED ) )
{
SfxObjectShell* pDocShell = SfxViewShell::Current()->GetObjectShell();
// if it is no export, warn user that the signature will be removed
if ( SignatureState::OK == nDocumentSignatureState
if ( !pDocShell->IsRememberingSignature()
&& (SignatureState::OK == nDocumentSignatureState
|| SignatureState::INVALID == nDocumentSignatureState
|| SignatureState::NOTVALIDATED == nDocumentSignatureState
|| SignatureState::PARTIAL_OK == nDocumentSignatureState)
|| SignatureState::PARTIAL_OK == nDocumentSignatureState) )
{
std::unique_ptr<weld::MessageDialog> xMessageBox(Application::CreateMessageDialog(SfxStoringHelper::GetModelWindow(xModel),
VclMessageType::Question, VclButtonsType::YesNo, SfxResId(RID_SVXSTR_XMLSEC_QUERY_LOSINGSIGNATURE)));
diff --git a/sfx2/source/doc/objserv.cxx b/sfx2/source/doc/objserv.cxx
index 78c4fd0..f321cbfc 100644
--- a/sfx2/source/doc/objserv.cxx
+++ b/sfx2/source/doc/objserv.cxx
@@ -532,6 +532,8 @@ void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq)
sal_uInt16 nId = rReq.GetSlot();
bool bHaveWeSigned = false;
if( SID_SIGNATURE == nId || SID_MACRO_SIGNATURE == nId )
{
if ( QueryHiddenInformation( HiddenWarningFact::WhenSigning, nullptr ) == RET_YES )
@@ -541,7 +543,8 @@ void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq)
uno::Reference<security::XCertificate> xCertificate = GetSignPDFCertificate();
if (xCertificate.is())
{
SignDocumentContentUsingCertificate(xCertificate);
bHaveWeSigned |= SignDocumentContentUsingCertificate(xCertificate);
// Reload to show how the PDF actually looks like after signing. This also
// changes "finish signing" on the infobar back to "sign document" as a side
@@ -568,14 +571,31 @@ void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq)
}
else
{
SignDocumentContent(pDialogParent);
bHaveWeSigned |= SignDocumentContent(pDialogParent);
}
}
else
{
SignScriptingContent(pDialogParent);
bHaveWeSigned |= SignScriptingContent(pDialogParent);
}
}
if ( bHaveWeSigned && HasValidSignatures() )
{
std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog( pDialogParent,
VclMessageType::Question, VclButtonsType::YesNo, SfxResId(STR_QUERY_REMEMBERSIGNATURE)));
if (xBox->run() == RET_YES)
{
rSignatureInfosRemembered = GetDocumentSignatureInformation(false);
bRememberSignature = true;
}
else
{
rSignatureInfosRemembered = uno::Sequence< security::DocumentSignatureInformation >();
bRememberSignature = false;
}
}
return;
}
@@ -1207,6 +1227,9 @@ void SfxObjectShell::ExecFile_Impl(SfxRequest &rReq)
}
}
if (nId == SID_SAVEDOC && bRememberSignature && rSignatureInfosRemembered.hasElements())
ResignDocument(rSignatureInfosRemembered);
rReq.SetReturnValue( SfxBoolItem(0, nErrorCode == ERRCODE_NONE ) );
ResetError();
@@ -1527,9 +1550,10 @@ void SfxObjectShell::GetState_Impl(SfxItemSet &rSet)
aInfobarType = InfobarType::DANGER;
break;
case SignatureState::INVALID:
sMessage = SfxResId(STR_SIGNATURE_INVALID);
// If we are remembering the certificates, it should be kept as valid
sMessage = SfxResId(bRememberSignature ? STR_SIGNATURE_OK : STR_SIGNATURE_INVALID);
// Warning only, I've tried Danger and it looked too scary
aInfobarType = InfobarType::WARNING;
aInfobarType = ( bRememberSignature ? InfobarType::INFO : InfobarType::WARNING );
break;
case SignatureState::NOTVALIDATED:
sMessage = SfxResId(STR_SIGNATURE_NOTVALIDATED);
@@ -1880,11 +1904,15 @@ bool SfxObjectShell::PrepareForSigning(weld::Window* pDialogParent)
if (nVersion >= SvtSaveOptions::ODFSVER_012)
{
OUString sQuestion(bHasSign ? SfxResId(STR_XMLSEC_QUERY_SAVESIGNEDBEFORESIGN) : SfxResId(RID_SVXSTR_XMLSEC_QUERY_SAVEBEFORESIGN));
std::unique_ptr<weld::MessageDialog> xQuestion(Application::CreateMessageDialog(pDialogParent,
std::unique_ptr<weld::MessageDialog> xQuestion;
if (!bRememberSignature)
{
xQuestion = std::unique_ptr<weld::MessageDialog>(Application::CreateMessageDialog(pDialogParent,
VclMessageType::Question, VclButtonsType::YesNo, sQuestion));
}
if (xQuestion->run() == RET_YES)
if ( bRememberSignature || ( xQuestion != nullptr && xQuestion->run() == RET_YES ) )
{
sal_uInt16 nId = SID_SAVEDOC;
if ( !GetMedium() || GetMedium()->GetName().isEmpty() )
@@ -1932,7 +1960,7 @@ bool SfxObjectShell::PrepareForSigning(weld::Window* pDialogParent)
// the document is not modified currently, so it can not become modified after signing
pImpl->m_bAllowModifiedBackAfterSigning = false;
if ( IsEnableSetModified() )
if ( IsEnableSetModified() || /*bRememberSignature == */true )
{
EnableSetModified( false );
pImpl->m_bAllowModifiedBackAfterSigning = true;
@@ -1968,7 +1996,7 @@ void SfxObjectShell::AfterSigning(bool bSignSuccess, bool bSignScriptingContent)
if ( bSignSuccess )
RecheckSignature(bSignScriptingContent);
if ( pImpl->m_bAllowModifiedBackAfterSigning )
if ( pImpl->m_bAllowModifiedBackAfterSigning || /* bRememberSignature ==*/ true )
EnableSetModified();
}
@@ -2041,17 +2069,36 @@ SignatureState SfxObjectShell::GetDocumentSignatureState()
return ImplGetSignatureState();
}
void SfxObjectShell::SignDocumentContent(weld::Window* pDialogParent)
bool SfxObjectShell::SignDocumentContent(weld::Window* pDialogParent)
{
if (!PrepareForSigning(pDialogParent))
return;
return false;
if (CheckIsReadonly(false, pDialogParent))
return;
return false;
bool bSignSuccess = GetMedium()->SignContents_Impl(pDialogParent, false, HasValidSignatures());
AfterSigning(bSignSuccess, false);
return bSignSuccess;
}
bool SfxObjectShell::ResignDocument(uno::Sequence< security::DocumentSignatureInformation >& rSignaturesInfo)
{
bool bSignSuccess = true;
// This should be at most one element, automatic iteration to avoid pointing issues in case no signs
for (auto & rInfo : rSignaturesInfo)
{
auto xCert = rInfo.Signer;
if (xCert.is())
{
bSignSuccess &= SignDocumentContentUsingCertificate(xCert);
}
}
return bSignSuccess;
}
bool SfxObjectShell::SignDocumentContentUsingCertificate(const Reference<XCertificate>& xCertificate)
@@ -2162,17 +2209,19 @@ SignatureState SfxObjectShell::GetScriptingSignatureState()
return ImplGetSignatureState( true );
}
void SfxObjectShell::SignScriptingContent(weld::Window* pDialogParent)
bool SfxObjectShell::SignScriptingContent(weld::Window* pDialogParent)
{
if (!PrepareForSigning(pDialogParent))
return;
return false;
if (CheckIsReadonly(true, pDialogParent))
return;
return false;
bool bSignSuccess = GetMedium()->SignContents_Impl(pDialogParent, true, HasValidSignatures());
AfterSigning(bSignSuccess, true);
return bSignSuccess;
}
const uno::Sequence<sal_Int8>& SfxObjectShell::getUnoTunnelId()
diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx b/xmlsecurity/source/component/documentdigitalsignatures.cxx
index 990fa5d..0fd029f 100644
--- a/xmlsecurity/source/component/documentdigitalsignatures.cxx
+++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx
@@ -869,7 +869,13 @@ bool DocumentDigitalSignatures::signWithCertificateImpl(
aSignatureManager.setSignatureStream(xStream);
aSignatureManager.setModel(xModel);
Reference<XXMLSecurityContext> xSecurityContext = aSignatureManager.getSecurityContext();
Reference<XXMLSecurityContext> xSecurityContext;
Reference<XServiceInfo> xServiceInfo(xCertificate, UNO_QUERY);
if (xServiceInfo->getImplementationName()
== "com.sun.star.xml.security.gpg.XCertificate_GpgImpl")
xSecurityContext = aSignatureManager.getGpgSecurityContext();
else
xSecurityContext = aSignatureManager.getSecurityContext();
sal_Int32 nSecurityId;