File: testremotewipe.cpp

package info (click to toggle)
nextcloud-desktop 4.0.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 40,404 kB
  • sloc: cpp: 118,401; objc: 752; python: 606; sh: 395; ansic: 391; ruby: 174; makefile: 44; javascript: 32; xml: 6
file content (147 lines) | stat: -rw-r--r-- 6,093 bytes parent folder | download
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
/*
 * SPDX-FileCopyrightText: 2019 Nextcloud GmbH and Nextcloud contributors
 * SPDX-License-Identifier: CC0-1.0
 * 
 * This software is in the public domain, furnished "as is", without technical
 * support, and with no warranty, express or implied, as to its usefulness for
 * any purpose.
 */

#include <qglobal.h>
#include <QtTest>

#include "remotewipe.h"
#include "accountmanager.h"

#include "folderman.h"
#include "account.h"
#include "accountstate.h"
#include "configfile.h"
#include "logger.h"

#include "testhelper.h"

#include "syncenginetestutils.h"

using namespace OCC;

class TestRemoteWipe: public QObject
{
    Q_OBJECT

private slots:
    void initTestCase()
    {
        OCC::Logger::instance()->setLogFlush(true);
        OCC::Logger::instance()->setLogDebug(true);

        QStandardPaths::setTestModeEnabled(true);
    }

    void testRemoteWipe()
    {
        auto dir = QTemporaryDir {};
        ConfigFile::setConfDir(dir.path()); // we don't want to pollute the user's config file

        // RemoteWipe needs FolderMan for actually wiping local data
        FolderMan fm;
        auto folderMan = FolderMan::instance();
        QVERIFY(folderMan);

        // RemoteWipe also needs an account present in the AccountManager
        FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
        auto account = fakeFolder.account();
        auto accountState = AccountManager::instance()->addAccount(account);

        // retrieve the RemoteWipe instance created from the real AccountState,
        // and replace its QNetworkAccessManager with our own one for testing
        auto remoteWipe = FakeAccountState::remoteWipe(accountState);
        auto fakeQnam = new FakeQNAM({});
        remoteWipe->_networkManager->deleteLater();
        remoteWipe->_networkManager = fakeQnam;

        // let FolderMan know about our sync folder
        FolderMan::instance()->addFolder(accountState, folderDefinition(fakeFolder.localPath()));

        bool revokeAppPassword = false; // whether respond with 401 to requests
        bool doWipe = false;            // whether a remote wipe should be done

        const auto fakeQnamOverride = [&](const QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *device) -> QNetworkReply * {
            Q_UNUSED(device)
            if (!revokeAppPassword) {
                qDebug() << "App password not revoked";
                return nullptr;
            }

            const auto requestUrl = request.url();
            const auto requestPath = requestUrl.path();

            if (op == QNetworkAccessManager::Operation::DeleteOperation && requestPath.endsWith("/ocs/v2.php/core/apppassword")) {
                qDebug() << "Responding success for app password deletion";
                // allow deletion of appPassword to succeed
                return new FakeJsonReply(op, request, this, 200);
            }

            if (doWipe) {
                qDebug() << "Wipe enabled";
                if (requestPath.endsWith("/index.php/core/wipe/check")) {
                    qDebug() << "Responding with wipe=true";
                    return new FakeJsonReply(op, request, this, 200, QJsonDocument::fromJson(R"({"wipe": true})"));
                } else if (requestPath.endsWith("/index.php/core/wipe/success")) {
                    qDebug() << "Responding with successful wipe";
                    return new FakeJsonReply(op, request, this, 200, QJsonDocument::fromJson(R"({})"));
                }
            }

            qDebug() << "Responding with unauthorised";
            auto errorReply = new FakeErrorReply(op, request, this, 401);
            errorReply->setError(QNetworkReply::AuthenticationRequiredError, QLatin1String("Unauthorised"));

            return errorReply;
        };
        fakeFolder.setServerOverride(fakeQnamOverride);
        fakeQnam->setOverride(fakeQnamOverride);

        const auto localFolderExists = [&fakeFolder]() -> bool {
            return QDir(fakeFolder.localPath()).exists();
        };

        // initial sync to ensure we've had a working connection
        qDebug() << "Test: Initial sync works";
        QVERIFY(fakeFolder.syncOnce());

        // just revoking the app password -> no remote wipe should be done
        qDebug() << "Test: App password revoked, no remote wipe triggered";
        revokeAppPassword = true;
        QVERIFY(!fakeFolder.syncOnce());
        // `Account` will try to retrieve the password from the keychain,
        // however during testing the password received from it will be empty.
        // An empty password will not perform the wipe check at all.
        // Therefore: call the slot which `Account` connects its
        // `appPasswordRetrieved` signal directly on the remoteWipe instance
        remoteWipe->startCheckJobWithAppPassword("password");
        QTest::qWait(500); // wait a bit to process events
        // ensure the account was not removed and the sync folder is still present
        QCOMPARE(AccountManager::instance()->accounts().size(), 1);
        QVERIFY2(localFolderExists(), "Local sync folder should exist as no wipe was requested");

        // hack for test: close the journal db of FakeFolder, as FolderMan::addFolder creates its own
        // as long as the test DB is open, removing files will break on e.g. Windows
        fakeFolder.syncJournal().close();

        // server tells us to wipe the local data
        qDebug() << "Test: Server tells us to remote wipe";
        doWipe = true;
        // ensure folder exists before performing the wipe
        QVERIFY2(localFolderExists(), "Local sync folder should exist before wiping");
        remoteWipe->startCheckJobWithAppPassword("password");
        QTest::qWait(500); // wait a bit to process events
        // account should now be gone
        QCOMPARE(AccountManager::instance()->accounts().size(), 0);
        // local folder should now be gone
        QVERIFY2(!localFolderExists(), "Local sync folder should be removed after wiping");
    }
};

QTEST_GUILESS_MAIN(TestRemoteWipe)
#include "testremotewipe.moc"