mirror of https://github.com/nymea/nymea.git
Add user database rotation if the database is broken.
parent
19a3a93980
commit
844f7a53a8
|
|
@ -514,7 +514,7 @@ void NymeaCore::init() {
|
|||
m_ruleEngine = new RuleEngine(this);
|
||||
|
||||
qCDebug(dcApplication()) << "Creating User Manager";
|
||||
m_userManager = new UserManager(this);
|
||||
m_userManager = new UserManager(NymeaSettings::settingsPath() + "/user-db.sqlite", this);
|
||||
|
||||
qCDebug(dcApplication) << "Creating Server Manager";
|
||||
m_serverManager = new ServerManager(m_configuration, this);
|
||||
|
|
|
|||
|
|
@ -35,16 +35,28 @@
|
|||
|
||||
namespace nymeaserver {
|
||||
|
||||
UserManager::UserManager(QObject *parent) : QObject(parent)
|
||||
UserManager::UserManager(const QString &dbName, QObject *parent):
|
||||
QObject(parent)
|
||||
{
|
||||
m_db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), "users");
|
||||
m_db.setDatabaseName(NymeaSettings::settingsPath() + "/user-db.sqlite");
|
||||
m_db.setDatabaseName(dbName);
|
||||
|
||||
if (!m_db.open()) {
|
||||
qCWarning(dcUserManager) << "Error opening users database:" << m_db.lastError().driverText();
|
||||
return;
|
||||
qCDebug(dcUserManager()) << "Opening user database" << m_db.databaseName();
|
||||
|
||||
if (!m_db.isValid()) {
|
||||
qCWarning(dcUserManager()) << "The database is not valid:" << m_db.lastError().driverText() << m_db.lastError().databaseText();
|
||||
rotate(m_db.databaseName());
|
||||
}
|
||||
|
||||
if (!initDB()) {
|
||||
qCWarning(dcUserManager()) << "Error initializing user database. Trying to correct it.";
|
||||
if (QFileInfo(m_db.databaseName()).exists()) {
|
||||
rotate(m_db.databaseName());
|
||||
if (!initDB()) {
|
||||
qCWarning(dcLogEngine()) << "Error fixing user database. Giving up. Users can't be stored.";
|
||||
}
|
||||
}
|
||||
}
|
||||
initDB();
|
||||
|
||||
m_pushButtonDBusService = new PushButtonDBusService("/io/guh/nymead/UserManager", this);
|
||||
connect(m_pushButtonDBusService, &PushButtonDBusService::pushButtonPressed, this, &UserManager::onPushButtonPressed);
|
||||
|
|
@ -286,13 +298,49 @@ bool UserManager::verifyToken(const QByteArray &token)
|
|||
return true;
|
||||
}
|
||||
|
||||
void UserManager::initDB()
|
||||
bool UserManager::initDB()
|
||||
{
|
||||
if (!m_db.tables().contains("users")) {
|
||||
m_db.exec("CREATE TABLE users (username VARCHAR(40) UNIQUE, password VARCHAR(100), salt VARCHAR(100));");
|
||||
m_db.close();
|
||||
|
||||
if (!m_db.open()) {
|
||||
qCWarning(dcUserManager()) << "Can't open user database. Init failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_db.tables().contains("users")) {
|
||||
qCDebug(dcUserManager()) << "Empty user database. Setting up metadata...";
|
||||
m_db.exec("CREATE TABLE users (username VARCHAR(40) UNIQUE, password VARCHAR(100), salt VARCHAR(100));");
|
||||
if (m_db.lastError().isValid()) {
|
||||
qCWarning(dcUserManager) << "Error initualizing user database. Driver error:" << m_db.lastError().driverText() << "Database error:" << m_db.lastError().databaseText();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_db.tables().contains("tokens")) {
|
||||
qCDebug(dcUserManager()) << "Empty user database. Setting up metadata...";
|
||||
m_db.exec("CREATE TABLE tokens (id VARCHAR(40) UNIQUE, username VARCHAR(40), token VARCHAR(100) UNIQUE, creationdate DATETIME, devicename VARCHAR(40));");
|
||||
if (m_db.lastError().isValid()) {
|
||||
qCWarning(dcUserManager()) << "Error initualizing user database. Driver error:" << m_db.lastError().driverText() << "Database error:" << m_db.lastError().databaseText();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
qCDebug(dcUserManager()) << "User database initialized successfully.";
|
||||
return true;
|
||||
}
|
||||
|
||||
void UserManager::rotate(const QString &dbName)
|
||||
{
|
||||
int index = 1;
|
||||
while (QFileInfo(QString("%1.%2").arg(dbName).arg(index)).exists()) {
|
||||
index++;
|
||||
}
|
||||
qCDebug(dcUserManager()) << "Backing up old database file to" << QString("%1.%2").arg(dbName).arg(index);
|
||||
QFile f(dbName);
|
||||
if (!f.rename(QString("%1.%2").arg(dbName).arg(index))) {
|
||||
qCWarning(dcUserManager()) << "Error backing up old database.";
|
||||
} else {
|
||||
qCDebug(dcUserManager()) << "Successfully moved old database";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public:
|
|||
UserErrorPermissionDenied
|
||||
};
|
||||
|
||||
explicit UserManager(QObject *parent = 0);
|
||||
explicit UserManager(const QString &dbName, QObject *parent = 0);
|
||||
|
||||
bool initRequired() const;
|
||||
QStringList users() const;
|
||||
|
|
@ -68,7 +68,8 @@ signals:
|
|||
void pushButtonAuthFinished(int transactionId, bool success, const QByteArray &token);
|
||||
|
||||
private:
|
||||
void initDB();
|
||||
bool initDB();
|
||||
void rotate(const QString &dbName);
|
||||
bool validateUsername(const QString &username) const;
|
||||
bool validateToken(const QByteArray &token) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,3 +21,4 @@ SUBDIRS = versioning \
|
|||
#coap \ # temporary removed until fixed
|
||||
configurations \
|
||||
timemanager \
|
||||
userloading \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,85 @@
|
|||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2018 Simon Stürz <simon.stuerz@guh.io> *
|
||||
* *
|
||||
* This file is part of nymea. *
|
||||
* *
|
||||
* nymea is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
**
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with nymea. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <QtTest>
|
||||
|
||||
#include "logging/logengine.h"
|
||||
#include "logging/logvaluetool.h"
|
||||
|
||||
#include "usermanager.h"
|
||||
|
||||
using namespace nymeaserver;
|
||||
|
||||
class TestUserLoading: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TestUserLoading(QObject* parent = nullptr);
|
||||
|
||||
protected slots:
|
||||
void initTestCase();
|
||||
|
||||
private slots:
|
||||
void testLogfileRotation();
|
||||
|
||||
};
|
||||
|
||||
TestUserLoading::TestUserLoading(QObject *parent): QObject(parent)
|
||||
{
|
||||
|
||||
Q_INIT_RESOURCE(userloading);
|
||||
}
|
||||
|
||||
void TestUserLoading::initTestCase()
|
||||
{
|
||||
// Important for settings
|
||||
QCoreApplication::instance()->setOrganizationName("nymea-test");
|
||||
}
|
||||
|
||||
void TestUserLoading::testLogfileRotation()
|
||||
{
|
||||
// Create UserManager with log db from resource file
|
||||
QString temporaryDbName = "/tmp/nymea-test/user-db-broken.sqlite";
|
||||
QString rotatedDbName = "/tmp/nymea-test/user-db-broken.sqlite.1";
|
||||
|
||||
// Remove the files if there are some left
|
||||
if (QFile::exists(temporaryDbName))
|
||||
QVERIFY(QFile(temporaryDbName).remove());
|
||||
|
||||
if (QFile::exists(rotatedDbName))
|
||||
QVERIFY(QFile(rotatedDbName).remove());
|
||||
|
||||
// Copy broken user db from resources to default settings path and set permissions
|
||||
qDebug() << "Copy broken user db to" << temporaryDbName;
|
||||
QVERIFY(QFile::copy(":/user-db-broken.sqlite", temporaryDbName));
|
||||
QVERIFY(QFile::setPermissions(temporaryDbName, QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup | QFile::ReadOther));
|
||||
|
||||
QVERIFY(!QFile::exists(rotatedDbName));
|
||||
UserManager *userManager = new UserManager(temporaryDbName, this);
|
||||
QVERIFY(QFile::exists(rotatedDbName));
|
||||
|
||||
delete userManager;
|
||||
|
||||
QVERIFY(QFile(temporaryDbName).remove());
|
||||
QVERIFY(QFile(rotatedDbName).remove());
|
||||
}
|
||||
|
||||
#include "testuserloading.moc"
|
||||
QTEST_MAIN(TestUserLoading)
|
||||
Binary file not shown.
|
|
@ -0,0 +1,6 @@
|
|||
include(../../../nymea.pri)
|
||||
include(../autotests.pri)
|
||||
|
||||
RESOURCES += userloading.qrc
|
||||
TARGET = userloading
|
||||
SOURCES += testuserloading.cpp
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>user-db-broken.sqlite</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
Loading…
Reference in New Issue