mirror of
https://github.com/sqlitebrowser/sqlitebrowser.git
synced 2026-01-19 18:40:13 -06:00
Add initial SQLCipher support
Add some basic initial support for SQLCipher. Note that this is more of a POC than a final implementation. This commit adds an option called 'sqlcipher' to the cmake and qmake projects which - when enabled - replaces the default SQLite3 include and library files by their SQLCipher counter-parts. Especially on MacOS X there might be some more work required in finding the correct include paths. The SQLCipher library supports unencrypted databases, too, so even if the option is enabled the program behaves like before. You can see the difference, though, in the About Dialog where the SQLite version string will say 'SQLCipher version xy'. When the sqlcipher option is enabled and you try to open a file which is neither a project file nor a normal SQLite3 database it is assumed now that the file is an encypted database. There is no way to tell between an invalid file and an encypted file, so in both cases a password dialog pops up. When the correct password and page size are entered the file is opened and can be edited like any other database before. Creating encrypted databases isn't supported yet. So for testing you need to fall back to the sqlcipher command line tool. See issue #12.
This commit is contained in:
@@ -29,7 +29,7 @@ endif()
|
||||
set(SQLB_HDR
|
||||
src/gen_version.h
|
||||
src/sqlitetypes.h
|
||||
src/csvparser.h
|
||||
src/csvparser.h
|
||||
src/grammar/sqlite3TokenTypes.hpp
|
||||
src/grammar/Sqlite3Lexer.hpp
|
||||
src/grammar/Sqlite3Parser.hpp
|
||||
@@ -54,6 +54,7 @@ set(SQLB_MOC_HDR
|
||||
src/sqltextedit.h
|
||||
src/DbStructureModel.h
|
||||
src/Application.h
|
||||
src/sqlite.h
|
||||
)
|
||||
|
||||
set(SQLB_SRC
|
||||
@@ -179,13 +180,21 @@ if(APPLE)
|
||||
add_definitions(-DCHECKNEWVERSION)
|
||||
endif(APPLE)
|
||||
|
||||
# SQLCipher option
|
||||
if(sqlcipher)
|
||||
add_definitions(-DSQLCIPHER)
|
||||
set(LIBSQLITE_NAME sqlcipher)
|
||||
else(sqlcipher)
|
||||
set(LIBSQLITE_NAME sqlite3)
|
||||
endif(sqlcipher)
|
||||
|
||||
# add extra library path for MacOS and FreeBSD
|
||||
set(EXTRAPATH APPLE OR ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
|
||||
if(EXTRAPATH)
|
||||
find_library(LIBSQLITE sqlite3 HINTS /usr/local/lib /usr/local/opt/sqlite/lib)
|
||||
find_library(LIBSQLITE ${LIBSQLITE_NAME} HINTS /usr/local/lib /usr/local/opt/sqlite/lib)
|
||||
set(ADDITIONAL_INCLUDE_PATHS /usr/local/include /usr/local/opt/sqlite/include)
|
||||
else(EXTRAPATH)
|
||||
find_library(LIBSQLITE sqlite3)
|
||||
find_library(LIBSQLITE ${LIBSQLITE_NAME})
|
||||
endif(EXTRAPATH)
|
||||
|
||||
include_directories(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "AboutDialog.h"
|
||||
#include "ui_AboutDialog.h"
|
||||
#include "gen_version.h"
|
||||
#include <sqlite3.h>
|
||||
#include "sqlite.h"
|
||||
|
||||
AboutDialog::AboutDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
@@ -12,7 +12,11 @@ AboutDialog::AboutDialog(QWidget *parent) :
|
||||
|
||||
ui->label_version->setText(ui->label_version->text() + " " + APP_VERSION);
|
||||
ui->label_versionqt->setText(ui->label_versionqt->text() + " " + QT_VERSION_STR);
|
||||
#ifdef SQLCIPHER
|
||||
ui->label_versionsqlite->setText(ui->label_versionsqlite->text().replace("SQLite", "SQLCipher") + " " + SQLITE_VERSION);
|
||||
#else
|
||||
ui->label_versionsqlite->setText(ui->label_versionsqlite->text() + " " + SQLITE_VERSION);
|
||||
#endif
|
||||
}
|
||||
|
||||
AboutDialog::~AboutDialog()
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
#include "sqlitedb.h"
|
||||
#include "PreferencesDialog.h"
|
||||
#include "sqlitetablemodel.h"
|
||||
#include "sqlite.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
#include <sqlite3.h>
|
||||
|
||||
ExportCsvDialog::ExportCsvDialog(DBBrowserDB* db, QWidget* parent, const QString& query, const QString& selection)
|
||||
: QDialog(parent),
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "ui_ImportCsvDialog.h"
|
||||
#include "sqlitedb.h"
|
||||
#include "csvparser.h"
|
||||
#include "sqlite.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QProgressDialog>
|
||||
@@ -10,7 +11,6 @@
|
||||
#include <QTextCodec>
|
||||
#include <QCompleter>
|
||||
#include <QComboBox>
|
||||
#include <sqlite3.h>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QSettings>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "VacuumDialog.h"
|
||||
#include "DbStructureModel.h"
|
||||
#include "gen_version.h"
|
||||
#include "sqlite.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QFile>
|
||||
@@ -28,7 +29,6 @@
|
||||
#include <QScrollBar>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QElapsedTimer>
|
||||
#include <sqlite3.h>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QNetworkAccessManager>
|
||||
@@ -195,23 +195,30 @@ bool MainWindow::fileOpen(const QString& fileName, bool dontAddToRecentFiles)
|
||||
if(QFile::exists(wFile) )
|
||||
{
|
||||
fileClose();
|
||||
if(db.open(wFile))
|
||||
// Try opening it as a project file first
|
||||
if(loadProject(wFile))
|
||||
{
|
||||
statusEncodingLabel->setText(db.getPragma("encoding"));
|
||||
setCurrentFile(wFile);
|
||||
if(!dontAddToRecentFiles)
|
||||
addToRecentFilesMenu(wFile);
|
||||
retval = true;
|
||||
} else {
|
||||
// Failed opening file; so it might be a project file instead
|
||||
return loadProject(wFile);
|
||||
// No project file; so it should be a database file
|
||||
if(db.open(wFile))
|
||||
{
|
||||
statusEncodingLabel->setText(db.getPragma("encoding"));
|
||||
setCurrentFile(wFile);
|
||||
if(!dontAddToRecentFiles)
|
||||
addToRecentFilesMenu(wFile);
|
||||
openSqlTab(true);
|
||||
retval = true;
|
||||
} else {
|
||||
QMessageBox::warning(this, qApp->applicationName(), tr("Invalid file format."));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
loadExtensionsFromSettings();
|
||||
populateStructure();
|
||||
resetBrowser();
|
||||
if(ui->mainTab->currentIndex() == 2)
|
||||
loadPragmas();
|
||||
openSqlTab(true);
|
||||
}
|
||||
|
||||
return retval;
|
||||
@@ -1749,10 +1756,7 @@ bool MainWindow::loadProject(QString filename)
|
||||
xml.readNext(); // token == QXmlStreamReader::StartDocument
|
||||
xml.readNext(); // name == sqlb_project
|
||||
if(xml.name() != "sqlb_project")
|
||||
{
|
||||
QMessageBox::warning(this, qApp->applicationName(), tr("Invalid file format."));
|
||||
return false;
|
||||
}
|
||||
|
||||
addToRecentFilesMenu(filename);
|
||||
|
||||
|
||||
12
src/sqlite.h
Normal file
12
src/sqlite.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef SQLITE_H
|
||||
#define SQLITE_H
|
||||
|
||||
#ifdef SQLCIPHER
|
||||
#define SQLITE_TEMP_STORE 2
|
||||
#define SQLITE_HAS_CODEC
|
||||
#include <sqlcipher/sqlite3.h>
|
||||
#else
|
||||
#include <sqlite3.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "sqlitedb.h"
|
||||
#include "sqlitetablemodel.h"
|
||||
#include "sqlite.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QMessageBox>
|
||||
@@ -7,7 +8,7 @@
|
||||
#include <QApplication>
|
||||
#include <QSettings>
|
||||
#include <QDebug>
|
||||
#include <sqlite3.h>
|
||||
#include <QInputDialog>
|
||||
|
||||
// collation callbacks
|
||||
int collCompare(void* /*pArg*/, int /*eTextRepA*/, const void* sA, int /*eTextRepB*/, const void* sB)
|
||||
@@ -43,32 +44,62 @@ bool DBBrowserDB::getDirty() const
|
||||
return !savepointList.empty();
|
||||
}
|
||||
|
||||
bool DBBrowserDB::open ( const QString & db)
|
||||
bool DBBrowserDB::open(const QString& db)
|
||||
{
|
||||
bool ok=false;
|
||||
int err;
|
||||
|
||||
if (isOpen()) close();
|
||||
|
||||
//try to verify the SQLite version 3 file header
|
||||
QFile dbfile(db);
|
||||
if ( dbfile.open( QIODevice::ReadOnly ) ) {
|
||||
char buffer[16+1];
|
||||
dbfile.readLine(buffer, 16);
|
||||
QString contents = QString(buffer);
|
||||
dbfile.close();
|
||||
if (!contents.startsWith("SQLite format 3")) {
|
||||
lastErrorMessage = QObject::tr("File is not a SQLite 3 database");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
lastErrorMessage = QObject::tr("File could not be read");
|
||||
lastErrorMessage = QObject::tr("no error");
|
||||
|
||||
// Open database file
|
||||
if(sqlite3_open_v2(db.toUtf8(), &_db, SQLITE_OPEN_READWRITE, NULL) != SQLITE_OK)
|
||||
{
|
||||
lastErrorMessage = QString::fromUtf8((const char*)sqlite3_errmsg(_db));
|
||||
return false;
|
||||
}
|
||||
|
||||
lastErrorMessage = QObject::tr("no error");
|
||||
|
||||
err = sqlite3_open_v2(db.toUtf8(), &_db, SQLITE_OPEN_READWRITE, NULL);
|
||||
// Try reading from database
|
||||
bool done = false;
|
||||
do
|
||||
{
|
||||
QString statement = "SELECT COUNT(*) FROM sqlite_master;";
|
||||
QByteArray utf8Statement = statement.toUtf8();
|
||||
sqlite3_stmt* vm;
|
||||
const char* tail;
|
||||
err = sqlite3_prepare_v2(_db, utf8Statement, utf8Statement.length(), &vm, &tail);
|
||||
if(sqlite3_step(vm) != SQLITE_ROW)
|
||||
{
|
||||
#ifdef SQLCIPHER
|
||||
QString pass = QInputDialog::getText(0, qApp->applicationName(),
|
||||
QObject::tr("Couldn't read from database file. This means it is either not a valid SQLite3 "
|
||||
"database or it is encrypted.\nIn the latter case you can provide a passphrase to open the file. Note"
|
||||
"that only databases encrypted using SQLCipher are supported."));
|
||||
if(pass.isEmpty())
|
||||
{
|
||||
sqlite3_close(_db);
|
||||
_db = 0;
|
||||
return false;
|
||||
} else {
|
||||
int pagesize = QInputDialog::getInt(0, qApp->applicationName(),
|
||||
QObject::tr("If the database has been encrypted using a different page size than normally (i.e. 1024 bytes) this "
|
||||
"value is required, too."),
|
||||
1024, 0);
|
||||
if(pagesize == 0) pagesize = 1024;
|
||||
sqlite3_key(_db, pass.toUtf8(), pass.toUtf8().length());
|
||||
sqlite3_exec(_db, QString("PRAGMA cipher_page_size = %1;").arg(pagesize).toUtf8(), NULL, NULL, NULL);
|
||||
}
|
||||
#else
|
||||
sqlite3_close(_db);
|
||||
_db = 0;
|
||||
return false;
|
||||
#endif
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
sqlite3_finalize(vm);
|
||||
} while(!done);
|
||||
|
||||
// register collation callback
|
||||
sqlite3_collation_needed(_db, NULL, collation_needed);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "sqlitetablemodel.h"
|
||||
#include "sqlitedb.h"
|
||||
#include "sqlite.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QMessageBox>
|
||||
#include <QApplication>
|
||||
#include <sqlite3.h>
|
||||
|
||||
SqliteTableModel::SqliteTableModel(QObject* parent, DBBrowserDB* db, size_t chunkSize)
|
||||
: QAbstractTableModel(parent)
|
||||
|
||||
12
src/src.pro
12
src/src.pro
@@ -42,7 +42,8 @@ HEADERS += \
|
||||
SqlExecutionArea.h \
|
||||
VacuumDialog.h \
|
||||
DbStructureModel.h \
|
||||
Application.h
|
||||
Application.h \
|
||||
sqlite.h
|
||||
|
||||
SOURCES += \
|
||||
sqlitedb.cpp \
|
||||
@@ -88,6 +89,13 @@ TRANSLATIONS += \
|
||||
translations/sqlb_fr.ts \
|
||||
translations/sqlb_ru.ts
|
||||
|
||||
CONFIG(sqlcipher) {
|
||||
QMAKE_CXXFLAGS += -DENABLE_SQLCIPHER
|
||||
LIBS += -lsqlcipher
|
||||
} else {
|
||||
LIBS += -lsqlite3
|
||||
}
|
||||
|
||||
LIBPATH_QHEXEDIT=$$PWD/../libs/qhexedit
|
||||
LIBPATH_ANTLR=$$PWD/../libs/antlr-2.7.7
|
||||
LIBPATH_QCUSTOMPLOT=$$PWD/../libs/qcustomplot-source
|
||||
@@ -121,7 +129,7 @@ mac {
|
||||
|
||||
UI_DIR = .ui
|
||||
INCLUDEPATH += $$PWD/../libs/antlr-2.7.7 $$PWD/../libs/qhexedit $$PWD/../libs/qcustomplot-source $$PWD/..
|
||||
LIBS += -L$$LIBPATH_QHEXEDIT -L$$LIBPATH_ANTLR -L$$LIBPATH_QCUSTOMPLOT -lantlr -lqhexedit -lqcustomplot -lsqlite3
|
||||
LIBS += -L$$LIBPATH_QHEXEDIT -L$$LIBPATH_ANTLR -L$$LIBPATH_QCUSTOMPLOT -lantlr -lqhexedit -lqcustomplot
|
||||
DEPENDPATH += $$PWD/../libs/antlr-2.7.7 $$PWD/../libs/qhexedit $$PWD/../libs/qcustomplot-source
|
||||
|
||||
# Rules for creating/updating {ts|qm}-files
|
||||
|
||||
Reference in New Issue
Block a user