Skip to content

Commit

Permalink
libreofficekit: ask for password when loading encrypted documents
Browse files Browse the repository at this point in the history
Change-Id: I3b3b0c0e64965280c24842b0cf70a21b8abb4dfb
  • Loading branch information
Michael Stahl committed Jan 25, 2016
1 parent f3f305b commit 2b63e57
Show file tree
Hide file tree
Showing 8 changed files with 190 additions and 4 deletions.
5 changes: 5 additions & 0 deletions desktop/inc/lib/init.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,12 @@
#include <com/sun/star/frame/XStorable.hpp>
#include <com/sun/star/lang/XComponent.hpp>
#include <memory>
#include <map>
#include "../../source/inc/desktopdllapi.h"
#include <osl/thread.h>

class LOKInteractionHandler;

namespace desktop {
struct DESKTOP_DLLPUBLIC LibLODocument_Impl : public _LibreOfficeKitDocument
{
Expand All @@ -36,8 +39,10 @@ namespace desktop {
oslThread maThread;
LibreOfficeKitCallback mpCallback;
void *mpCallbackData;
std::map<OString, rtl::Reference<LOKInteractionHandler>> mInteractionMap;

LibLibreOffice_Impl();
~LibLibreOffice_Impl();
};
}

Expand Down
29 changes: 28 additions & 1 deletion desktop/source/lib/init.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,9 @@ static void lo_registerCallback (LibreOfficeKit* pThis,
LibreOfficeKitCallback pCallback,
void* pData);
static char* lo_getFilterTypes(LibreOfficeKit* pThis);
static void lo_setDocumentPassword(LibreOfficeKit* pThis,
const char* pURL,
const char* pPassword);

LibLibreOffice_Impl::LibLibreOffice_Impl()
: m_pOfficeClass( gOfficeClass.lock() )
Expand All @@ -456,13 +459,18 @@ LibLibreOffice_Impl::LibLibreOffice_Impl()
m_pOfficeClass->documentLoadWithOptions = lo_documentLoadWithOptions;
m_pOfficeClass->registerCallback = lo_registerCallback;
m_pOfficeClass->getFilterTypes = lo_getFilterTypes;
m_pOfficeClass->setDocumentPassword = lo_setDocumentPassword;

gOfficeClass = m_pOfficeClass;
}

pClass = m_pOfficeClass.get();
}

LibLibreOffice_Impl::~LibLibreOffice_Impl()
{
}

namespace
{

Expand Down Expand Up @@ -524,7 +532,10 @@ static LibreOfficeKitDocument* lo_documentLoadWithOptions(LibreOfficeKit* pThis,
uno::makeAny(OUString::createFromAscii(pOptions)),
beans::PropertyState_DIRECT_VALUE);

uno::Reference<task::XInteractionHandler2> xInteraction(new LOKInteractionHandler(::comphelper::getProcessComponentContext()));
rtl::Reference<LOKInteractionHandler> const pInteraction(
new LOKInteractionHandler(::comphelper::getProcessComponentContext(), pLib));
auto const pair(pLib->mInteractionMap.insert(std::make_pair(aURL.toUtf8(), pInteraction)));
uno::Reference<task::XInteractionHandler2> const xInteraction(pInteraction.get());
aFilterOptions[1].Name = "InteractionHandler";
aFilterOptions[1].Value <<= xInteraction;

Expand All @@ -543,6 +554,12 @@ static LibreOfficeKitDocument* lo_documentLoadWithOptions(LibreOfficeKit* pThis,
aURL, "_blank", 0,
aFilterOptions);

assert(!xComponent.is() || pair.second); // concurrent loading of same URL ought to fail
if (!pair.second)
{
pLib->mInteractionMap.erase(aURL.toUtf8());
}

if (!xComponent.is())
{
pLib->maLastExceptionMsg = "loadComponentFromURL returned an empty reference";
Expand Down Expand Up @@ -1616,6 +1633,16 @@ static char* lo_getFilterTypes(LibreOfficeKit* pThis)
return strdup(aStream.str().c_str());
}

static void lo_setDocumentPassword(LibreOfficeKit* pThis,
const char* pURL, const char* pPassword)
{
assert(pThis);
assert(pURL);
LibLibreOffice_Impl *const pLib = static_cast<LibLibreOffice_Impl*>(pThis);
assert(pLib->mInteractionMap.find(OString(pURL)) != pLib->mInteractionMap.end());
pLib->mInteractionMap.find(OString(pURL))->second->SetPassword(pPassword);
}

static void force_c_locale()
{
// force locale (and resource files loaded) to en-US
Expand Down
89 changes: 88 additions & 1 deletion desktop/source/lib/lokinteractionhandler.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,27 @@

#include "lokinteractionhandler.hxx"

#include <rtl/ref.hxx>
#include <cppuhelper/supportsservice.hxx>

#include <com/sun/star/task/XInteractionAbort.hpp>
#include <com/sun/star/task/XInteractionApprove.hpp>
#include <com/sun/star/task/XInteractionPassword2.hpp>
#include <com/sun/star/task/DocumentPasswordRequest2.hpp>

#include <../../inc/lib/init.hxx>

#include <LibreOfficeKit/LibreOfficeKitEnums.h>

using namespace com::sun::star;

LOKInteractionHandler::LOKInteractionHandler(uno::Reference<uno::XComponentContext> const & /*rxContext*/)
LOKInteractionHandler::LOKInteractionHandler(
uno::Reference<uno::XComponentContext> const & /*rxContext*/,
desktop::LibLibreOffice_Impl *const pLOKit)
: m_pLOKit(pLOKit)
, m_usePassword(false)
{
assert(m_pLOKit);
}

LOKInteractionHandler::~LOKInteractionHandler()
Expand Down Expand Up @@ -72,6 +85,66 @@ throw (uno::RuntimeException, std::exception)
{
uno::Sequence<uno::Reference<task::XInteractionContinuation>> const &rContinuations = xRequest->getContinuations();

uno::Any const request(xRequest->getRequest());
task::DocumentPasswordRequest2 passwordRequest;
if (request >>= passwordRequest)
{
OString const url(passwordRequest.Name.toUtf8());
m_pLOKit->mpCallback(passwordRequest.IsRequestPasswordToModify
? LOK_CALLBACK_DOCUMENT_PASSWORD
: LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY,
url.getStr(),
m_pLOKit->mpCallbackData);

// block until SetPassword is called
m_havePassword.wait(nullptr);
m_havePassword.reset();

for (sal_Int32 i = 0; i < rContinuations.getLength(); ++i)
{
if (m_usePassword)
{
if (passwordRequest.IsRequestPasswordToModify)
{
uno::Reference<task::XInteractionPassword2> const xIPW2(
rContinuations[i], uno::UNO_QUERY);
xIPW2->setPasswordToModify(m_Password);
xIPW2->select();
}
else
{
uno::Reference<task::XInteractionPassword> const xIPW(
rContinuations[i], uno::UNO_QUERY);
if (xIPW.is())
{
xIPW->setPassword(m_Password);
xIPW->select();
}
}
}
else
{
if (passwordRequest.IsRequestPasswordToModify)
{
uno::Reference<task::XInteractionPassword2> const xIPW2(
rContinuations[i], uno::UNO_QUERY);
xIPW2->setRecommendReadOnly(true);
xIPW2->select();
}
else
{
uno::Reference<task::XInteractionAbort> const xAbort(
rContinuations[i], uno::UNO_QUERY);
if (xAbort.is())
{
xAbort->select();
}
}
}
}
return sal_True;
}

// TODO: add LOK api that allows handling this for real, for the moment we
// just set the interaction as 'Approved'
for (sal_Int32 i = 0; i < rContinuations.getLength(); ++i)
Expand All @@ -84,4 +157,18 @@ throw (uno::RuntimeException, std::exception)
return sal_True;
}

void LOKInteractionHandler::SetPassword(char const*const pPassword)
{
if (pPassword)
{
m_Password = OUString(pPassword, strlen(pPassword), RTL_TEXTENCODING_UTF8);
m_usePassword = true;
}
else
{
m_usePassword = false;
}
m_havePassword.set();
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
15 changes: 14 additions & 1 deletion desktop/source/lib/lokinteractionhandler.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@
#ifndef INCLUDED_DESKTOP_SOURCE_LIB_LOKINTERACTIONHANDLER_HXX
#define INCLUDED_DESKTOP_SOURCE_LIB_LOKINTERACTIONHANDLER_HXX

#include <osl/conditn.hxx>
#include <cppuhelper/implbase.hxx>

#include <com/sun/star/lang/XInitialization.hpp>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/task/InteractionHandler.hpp>

namespace desktop { struct LibLibreOffice_Impl; }

/** InteractionHandler is an interface that provides the user with various dialogs / error messages.
We need an own implementation for the LibreOfficeKit so that we can route the
Expand All @@ -38,11 +41,21 @@ class LOKInteractionHandler: public cppu::WeakImplHelper<com::sun::star::lang::X
com::sun::star::lang::XInitialization,
com::sun::star::task::XInteractionHandler2>
{
private:
desktop::LibLibreOffice_Impl * m_pLOKit;
OUString m_Password;
bool m_usePassword;
osl::Condition m_havePassword;

LOKInteractionHandler(const LOKInteractionHandler&) = delete;
LOKInteractionHandler& operator=(const LOKInteractionHandler&) = delete;

public:
explicit LOKInteractionHandler(com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext> const & rxContext);
void SetPassword(char const* pPassword);

explicit LOKInteractionHandler(
com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext> const & rxContext,
desktop::LibLibreOffice_Impl *);

virtual ~LOKInteractionHandler();

Expand Down
5 changes: 5 additions & 0 deletions include/LibreOfficeKit/LibreOfficeKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ struct _LibreOfficeKitClass

/// @see lok::Office::getFilterTypes().
char* (*getFilterTypes) (LibreOfficeKit* pThis);

/// @see lok::Office::setDocumentPassword().
void (*setDocumentPassword) (LibreOfficeKit* pThis,
char const* pURL,
char const* pPassword);
#endif

};
Expand Down
24 changes: 24 additions & 0 deletions include/LibreOfficeKit/LibreOfficeKit.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,30 @@ public:
{
return mpThis->pClass->getFilterTypes(mpThis);
}

/**
* Set password required for loading or editing a document.
*
* Loading the document is blocked until the password is provided.
*
* @param pURL the URL of the document, as sent to the callback
* @param pPassword the password, nullptr indicates no password
*
* In response to LOK_CALLBACK_DOCUMENT_PASSWORD, a vaild password
* will continue loading the document, an invalid password will
* result in another LOK_CALLBACK_DOCUMENT_PASSWORD request,
* and a NULL password will abort loading the document.
*
* In response to LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY, a vaild
* password will continue loading the document, an invalid password will
* result in another LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY request,
* and a NULL password will continue loading the document in read-only
* mode.
*/
inline void setDocumentPassword(char const* pURL, char const* pPassword)
{
mpThis->pClass->setDocumentPassword(mpThis, pURL, pPassword);
}
#endif // defined LOK_USE_UNSTABLE_API || defined LIBO_INTERNAL_ONLY
};

Expand Down
19 changes: 18 additions & 1 deletion include/LibreOfficeKit/LibreOfficeKitEnums.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,24 @@ typedef enum
/**
* The text content of the formula bar in Calc.
*/
LOK_CALLBACK_CELL_FORMULA
LOK_CALLBACK_CELL_FORMULA,

/**
* Loading a document requires a password.
*
* Loading the document is blocked until the password is provided via
* lok::Office::setDocumentPassword(). The document cannot be loaded
* without the password.
*/
LOK_CALLBACK_DOCUMENT_PASSWORD,

/**
* Editing a document requires a password.
*
* Loading the document is blocked until the password is provided via
* lok::Office::setDocumentPassword().
*/
LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY,
}
LibreOfficeKitCallbackType;

Expand Down
8 changes: 8 additions & 0 deletions libreofficekit/source/gtk/lokdocview.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,14 @@ globalCallback (gpointer pData)
g_signal_emit (pCallback->m_pDocView, doc_view_signals[LOAD_CHANGED], 0, 1.0);
}
break;
case LOK_CALLBACK_DOCUMENT_PASSWORD:
case LOK_CALLBACK_DOCUMENT_PASSWORD_TO_MODIFY:
{
char const*const pURL(pCallback->m_aPayload.c_str());
// TODO maybe allow more passwords
priv->m_pOffice->pClass->setDocumentPassword(priv->m_pOffice, pURL, "1");
}
break;
default:
g_assert(false);
break;
Expand Down

0 comments on commit 2b63e57

Please sign in to comment.