summaryrefslogtreecommitdiff
path: root/wsd/Storage.hpp
blob: 60c732757530d8878eddc3da52ef00e28192e34f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
 * 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/.
 */

// Storage abstraction.
#ifndef INCLUDED_STORAGE_HPP
#define INCLUDED_STORAGE_HPP

#include <set>
#include <string>

#include <Poco/URI.h>
#include <Poco/Util/Application.h>

#include "Auth.hpp"
#include "Log.hpp"
#include "Util.hpp"

/// Base class of all Storage abstractions.
class StorageBase
{
public:
    /// Represents basic file's attributes.
    /// Used for local and network files.
    class FileInfo
    {
    public:
        FileInfo(const std::string& filename,
                 const std::string& ownerId,
                 const Poco::Timestamp& modifiedTime,
                 size_t size)
            : _filename(filename),
              _ownerId(ownerId),
              _modifiedTime(modifiedTime),
              _size(size)
        {
        }

        bool isValid() const
        {
            // 0-byte files are valid; LO will open them as new docs.
            return !_filename.empty();
        }

        std::string _filename;
        std::string _ownerId;
        Poco::Timestamp _modifiedTime;
        size_t _size;
    };

    enum class SaveResult
    {
        OK,
        DISKFULL,
        UNAUTHORIZED,
        DOC_CHANGED, /* Document changed in storage */
        CONFLICT,
        FAILED
    };

    enum class LOOLStatusCode
    {
        DOC_CHANGED = 1010 // Document changed externally in storage
    };

    /// localStorePath the absolute root path of the chroot.
    /// jailPath the path within the jail that the child uses.
    StorageBase(const Poco::URI& uri,
                const std::string& localStorePath,
                const std::string& jailPath) :
        _uri(uri),
        _localStorePath(localStorePath),
        _jailPath(jailPath),
        _fileInfo("", "lool", Poco::Timestamp::fromEpochTime(0), 0),
        _isLoaded(false),
        _forceSave(false)
    {
        LOG_DBG("Storage ctor: " << uri.toString());
    }

    const std::string getUri() const { return _uri.toString(); }

    /// Returns the root path to the jailed file.
    const std::string& getRootFilePath() const { return _jailedFilePath; };

    bool isLoaded() const { return _isLoaded; }

    /// Asks the storage object to force overwrite to storage upon next save
    /// even if document turned out to be changed in storage
    void forceSave() { _forceSave = true; }

    /// Returns the basic information about the file.
    FileInfo getFileInfo() { return _fileInfo; }

    /// Returns a local file path for the given URI.
    /// If necessary copies the file locally first.
    virtual std::string loadStorageFileToLocal(const std::string& accessToken) = 0;

    /// Writes the contents of the file back to the source.
    virtual SaveResult saveLocalFileToStorage(const std::string& accessToken) = 0;

    static size_t getFileSize(const std::string& filename);

    /// Must be called at startup to configure.
    static void initialize();

    /// Storage object creation factory.
    static std::unique_ptr<StorageBase> create(const Poco::URI& uri,
                                               const std::string& jailRoot,
                                               const std::string& jailPath);
protected:

    /// Returns the root path of the jail directory of docs.
    std::string getLocalRootPath() const;

protected:
    const Poco::URI _uri;
    std::string _localStorePath;
    std::string _jailPath;
    std::string _jailedFilePath;
    FileInfo _fileInfo;
    bool _isLoaded;
    bool _forceSave;

    static bool FilesystemEnabled;
    static bool WopiEnabled;
    /// Allowed/denied WOPI hosts, if any and if WOPI is enabled.
    static Util::RegexListMatcher WopiHosts;
};

/// Trivial implementation of local storage that does not need do anything.
class LocalStorage : public StorageBase
{
public:
    LocalStorage(const Poco::URI& uri,
                 const std::string& localStorePath,
                 const std::string& jailPath) :
        StorageBase(uri, localStorePath, jailPath),
        _isCopy(false)
    {
        LOG_INF("LocalStorage ctor with localStorePath: [" << localStorePath <<
                "], jailPath: [" << jailPath << "], uri: [" << uri.toString() << "].");
    }

    class LocalFileInfo
    {
    public:
        LocalFileInfo(const std::string& userid,
                      const std::string& username)
            : _userid(userid),
              _username(username)
        {
        }

        std::string _userid;
        std::string _username;
    };

    /// Returns the URI specific file data
    /// Also stores the basic file information which can then be
    /// obtained using getFileInfo method
    std::unique_ptr<LocalFileInfo> getLocalFileInfo();

    std::string loadStorageFileToLocal(const std::string& accessToken) override;

    SaveResult saveLocalFileToStorage(const std::string& accessToken) override;

private:
    /// True if the jailed file is not linked but copied.
    bool _isCopy;
    static std::atomic<unsigned> LastLocalStorageId;
};

/// WOPI protocol backed storage.
class WopiStorage : public StorageBase
{
public:
    WopiStorage(const Poco::URI& uri,
                const std::string& localStorePath,
                const std::string& jailPath) :
        StorageBase(uri, localStorePath, jailPath),
        _wopiLoadDuration(0)
    {
        LOG_INF("WopiStorage ctor with localStorePath: [" << localStorePath <<
                "], jailPath: [" << jailPath << "], uri: [" << uri.toString() << "].");
    }

    class WOPIFileInfo
    {
    public:
        WOPIFileInfo(const std::string& userid,
                     const std::string& username,
                     const std::string& userExtraInfo,
                     const bool userCanWrite,
                     const std::string& postMessageOrigin,
                     const bool hidePrintOption,
                     const bool hideSaveOption,
                     const bool hideExportOption,
                     const bool enableOwnerTermination,
                     const bool disablePrint,
                     const bool disableExport,
                     const bool disableCopy,
                     const std::chrono::duration<double> callDuration)
            : _userid(userid),
              _username(username),
              _userCanWrite(userCanWrite),
              _postMessageOrigin(postMessageOrigin),
              _hidePrintOption(hidePrintOption),
              _hideSaveOption(hideSaveOption),
              _hideExportOption(hideExportOption),
              _enableOwnerTermination(enableOwnerTermination),
              _disablePrint(disablePrint),
              _disableExport(disableExport),
              _disableCopy(disableCopy),
              _callDuration(callDuration)
            {
                _userExtraInfo = userExtraInfo;
            }

        /// User id of the user accessing the file
        std::string _userid;
        /// Display Name of user accessing the file
        std::string _username;
        /// Extra info per user, typically mail and other links, as json.
        std::string _userExtraInfo;
        /// If user accessing the file has write permission
        bool _userCanWrite;
        /// WOPI Post message property
        std::string _postMessageOrigin;
        /// Hide print button from UI
        bool _hidePrintOption;
        /// Hide save button from UI
        bool _hideSaveOption;
        /// Hide 'Download as' button/menubar item from UI
        bool _hideExportOption;
        /// If WOPI host has enabled owner termination feature on
        bool _enableOwnerTermination;
        /// If WOPI host has allowed the user to print the document
        bool _disablePrint;
        /// If WOPI host has allowed the user to export the document
        bool _disableExport;
        /// If WOPI host has allowed the user to copy to/from the document
        bool _disableCopy;
        /// Time it took to call WOPI's CheckFileInfo
        std::chrono::duration<double> _callDuration;
    };

    /// Returns the response of CheckFileInfo WOPI call for URI that was
    /// provided during the initial creation of the WOPI storage.
    /// Also extracts the basic file information from the response
    /// which can then be obtained using getFileInfo()
    std::unique_ptr<WOPIFileInfo> getWOPIFileInfo(const std::string& accessToken);

    /// uri format: http://server/<...>/wopi*/files/<id>/content
    std::string loadStorageFileToLocal(const std::string& accessToken) override;

    SaveResult saveLocalFileToStorage(const std::string& accessToken) override;

    /// Total time taken for making WOPI calls during load
    std::chrono::duration<double> getWopiLoadDuration() const { return _wopiLoadDuration; }

private:
    // Time spend in loading the file from storage
    std::chrono::duration<double> _wopiLoadDuration;
};

/// WebDAV protocol backed storage.
class WebDAVStorage : public StorageBase
{
public:
    WebDAVStorage(const Poco::URI& uri,
                  const std::string& localStorePath,
                  const std::string& jailPath,
                  std::unique_ptr<AuthBase> authAgent) :
        StorageBase(uri, localStorePath, jailPath),
        _authAgent(std::move(authAgent))
    {
        LOG_INF("WebDAVStorage ctor with localStorePath: [" << localStorePath <<
                "], jailPath: [" << jailPath << "], uri: [" << uri.toString() << "].");
    }

    // Implement me
    // WebDAVFileInfo getWebDAVFileInfo(const Poco::URI& uriPublic);

    std::string loadStorageFileToLocal(const std::string& accessToken) override;

    SaveResult saveLocalFileToStorage(const std::string& accessToken) override;

private:
    std::unique_ptr<AuthBase> _authAgent;
};

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */