mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-03-29 17:38:02 -04:00
Improve CSV export and import capability
* Fixes #3541 * CSV export now includes TOTP settings, Entry Icon (database icon number only), Modified Time, and Created Time. * CSV import properly understands time in ISO 8601 format and Unix Timestamp. * CSV import will set the TOTP settings and entry icon based on the chosen column.
This commit is contained in:
parent
3f7e79cdf3
commit
7ac651763c
@ -465,7 +465,8 @@ void Entry::setTotp(QSharedPointer<Totp::Settings> settings)
|
|||||||
m_data.totpSettings.reset();
|
m_data.totpSettings.reset();
|
||||||
} else {
|
} else {
|
||||||
m_data.totpSettings = std::move(settings);
|
m_data.totpSettings = std::move(settings);
|
||||||
auto text = Totp::writeSettings(m_data.totpSettings, title(), username());
|
auto text = Totp::writeSettings(
|
||||||
|
m_data.totpSettings, resolveMultiplePlaceholders(title()), resolveMultiplePlaceholders(username()));
|
||||||
if (m_data.totpSettings->format != Totp::StorageFormat::LEGACY) {
|
if (m_data.totpSettings->format != Totp::StorageFormat::LEGACY) {
|
||||||
m_attributes->set(Totp::ATTRIBUTE_OTP, text, true);
|
m_attributes->set(Totp::ATTRIBUTE_OTP, text, true);
|
||||||
} else {
|
} else {
|
||||||
@ -493,6 +494,15 @@ QSharedPointer<Totp::Settings> Entry::totpSettings() const
|
|||||||
return m_data.totpSettings;
|
return m_data.totpSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Entry::totpSettingsString() const
|
||||||
|
{
|
||||||
|
if (m_data.totpSettings) {
|
||||||
|
return Totp::writeSettings(
|
||||||
|
m_data.totpSettings, resolveMultiplePlaceholders(title()), resolveMultiplePlaceholders(username()), true);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
void Entry::setUuid(const QUuid& uuid)
|
void Entry::setUuid(const QUuid& uuid)
|
||||||
{
|
{
|
||||||
Q_ASSERT(!uuid.isNull());
|
Q_ASSERT(!uuid.isNull());
|
||||||
|
@ -106,6 +106,7 @@ public:
|
|||||||
QString notes() const;
|
QString notes() const;
|
||||||
QString attribute(const QString& key) const;
|
QString attribute(const QString& key) const;
|
||||||
QString totp() const;
|
QString totp() const;
|
||||||
|
QString totpSettingsString() const;
|
||||||
QSharedPointer<Totp::Settings> totpSettings() const;
|
QSharedPointer<Totp::Settings> totpSettings() const;
|
||||||
int size() const;
|
int size() const;
|
||||||
|
|
||||||
|
@ -67,6 +67,10 @@ QString CsvExporter::exportHeader()
|
|||||||
addColumn(header, "Password");
|
addColumn(header, "Password");
|
||||||
addColumn(header, "URL");
|
addColumn(header, "URL");
|
||||||
addColumn(header, "Notes");
|
addColumn(header, "Notes");
|
||||||
|
addColumn(header, "TOTP");
|
||||||
|
addColumn(header, "Icon");
|
||||||
|
addColumn(header, "Last Modified");
|
||||||
|
addColumn(header, "Created");
|
||||||
return header + QString("\n");
|
return header + QString("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,6 +92,10 @@ QString CsvExporter::exportGroup(const Group* group, QString groupPath)
|
|||||||
addColumn(line, entry->password());
|
addColumn(line, entry->password());
|
||||||
addColumn(line, entry->url());
|
addColumn(line, entry->url());
|
||||||
addColumn(line, entry->notes());
|
addColumn(line, entry->notes());
|
||||||
|
addColumn(line, entry->totpSettingsString());
|
||||||
|
addColumn(line, QString::number(entry->iconNumber()));
|
||||||
|
addColumn(line, entry->timeInfo().lastModificationTime().toString(Qt::ISODate));
|
||||||
|
addColumn(line, entry->timeInfo().creationTime().toString(Qt::ISODate));
|
||||||
|
|
||||||
line.append("\n");
|
line.append("\n");
|
||||||
response.append(line);
|
response.append(line);
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "format/KeePass2Writer.h"
|
#include "format/KeePass2Writer.h"
|
||||||
#include "gui/MessageBox.h"
|
#include "gui/MessageBox.h"
|
||||||
#include "gui/MessageWidget.h"
|
#include "gui/MessageWidget.h"
|
||||||
|
#include "totp/totp.h"
|
||||||
|
|
||||||
// I wanted to make the CSV import GUI future-proof, so if one day you need a new field,
|
// I wanted to make the CSV import GUI future-proof, so if one day you need a new field,
|
||||||
// all you have to do is add a field to m_columnHeader, and the GUI will follow:
|
// all you have to do is add a field to m_columnHeader, and the GUI will follow:
|
||||||
@ -39,7 +40,8 @@ CsvImportWidget::CsvImportWidget(QWidget* parent)
|
|||||||
, m_comboModel(new QStringListModel(this))
|
, m_comboModel(new QStringListModel(this))
|
||||||
, m_columnHeader(QStringList() << QObject::tr("Group") << QObject::tr("Title") << QObject::tr("Username")
|
, m_columnHeader(QStringList() << QObject::tr("Group") << QObject::tr("Title") << QObject::tr("Username")
|
||||||
<< QObject::tr("Password") << QObject::tr("URL") << QObject::tr("Notes")
|
<< QObject::tr("Password") << QObject::tr("URL") << QObject::tr("Notes")
|
||||||
<< QObject::tr("Last Modified") << QObject::tr("Created"))
|
<< QObject::tr("TOTP") << QObject::tr("Icon") << QObject::tr("Last Modified")
|
||||||
|
<< QObject::tr("Created"))
|
||||||
, m_fieldSeparatorList(QStringList() << ","
|
, m_fieldSeparatorList(QStringList() << ","
|
||||||
<< ";"
|
<< ";"
|
||||||
<< "-"
|
<< "-"
|
||||||
@ -54,7 +56,7 @@ CsvImportWidget::CsvImportWidget(QWidget* parent)
|
|||||||
m_ui->messageWidget->setHidden(true);
|
m_ui->messageWidget->setHidden(true);
|
||||||
|
|
||||||
m_combos << m_ui->groupCombo << m_ui->titleCombo << m_ui->usernameCombo << m_ui->passwordCombo << m_ui->urlCombo
|
m_combos << m_ui->groupCombo << m_ui->titleCombo << m_ui->usernameCombo << m_ui->passwordCombo << m_ui->urlCombo
|
||||||
<< m_ui->notesCombo << m_ui->lastModifiedCombo << m_ui->createdCombo;
|
<< m_ui->notesCombo << m_ui->totpCombo << m_ui->iconCombo << m_ui->lastModifiedCombo << m_ui->createdCombo;
|
||||||
|
|
||||||
for (auto combo : m_combos) {
|
for (auto combo : m_combos) {
|
||||||
combo->setModel(m_comboModel);
|
combo->setModel(m_comboModel);
|
||||||
@ -206,17 +208,38 @@ void CsvImportWidget::writeDatabase()
|
|||||||
entry->setUrl(m_parserModel->data(m_parserModel->index(r, 4)).toString());
|
entry->setUrl(m_parserModel->data(m_parserModel->index(r, 4)).toString());
|
||||||
entry->setNotes(m_parserModel->data(m_parserModel->index(r, 5)).toString());
|
entry->setNotes(m_parserModel->data(m_parserModel->index(r, 5)).toString());
|
||||||
|
|
||||||
TimeInfo timeInfo;
|
|
||||||
if (m_parserModel->data(m_parserModel->index(r, 6)).isValid()) {
|
if (m_parserModel->data(m_parserModel->index(r, 6)).isValid()) {
|
||||||
qint64 lastModified = m_parserModel->data(m_parserModel->index(r, 6)).toString().toLongLong();
|
auto totp = Totp::parseSettings(m_parserModel->data(m_parserModel->index(r, 6)).toString());
|
||||||
if (lastModified) {
|
entry->setTotp(totp);
|
||||||
timeInfo.setLastModificationTime(Clock::datetimeUtc(lastModified * 1000));
|
}
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
int icon = m_parserModel->data(m_parserModel->index(r, 7)).toInt(&ok);
|
||||||
|
if (ok) {
|
||||||
|
entry->setIcon(icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeInfo timeInfo;
|
||||||
|
if (m_parserModel->data(m_parserModel->index(r, 8)).isValid()) {
|
||||||
|
auto datetime = m_parserModel->data(m_parserModel->index(r, 8)).toString();
|
||||||
|
if (datetime.contains(QRegularExpression("^\\d+$"))) {
|
||||||
|
timeInfo.setLastModificationTime(Clock::datetimeUtc(datetime.toLongLong() * 1000));
|
||||||
|
} else {
|
||||||
|
auto lastModified = QDateTime::fromString(datetime, Qt::ISODate);
|
||||||
|
if (lastModified.isValid()) {
|
||||||
|
timeInfo.setLastModificationTime(lastModified);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_parserModel->data(m_parserModel->index(r, 7)).isValid()) {
|
if (m_parserModel->data(m_parserModel->index(r, 9)).isValid()) {
|
||||||
qint64 created = m_parserModel->data(m_parserModel->index(r, 7)).toString().toLongLong();
|
auto datetime = m_parserModel->data(m_parserModel->index(r, 9)).toString();
|
||||||
if (created) {
|
if (datetime.contains(QRegularExpression("^\\d+$"))) {
|
||||||
timeInfo.setCreationTime(Clock::datetimeUtc(created * 1000));
|
timeInfo.setCreationTime(Clock::datetimeUtc(datetime.toLongLong() * 1000));
|
||||||
|
} else {
|
||||||
|
auto created = QDateTime::fromString(datetime, Qt::ISODate);
|
||||||
|
if (created.isValid()) {
|
||||||
|
timeInfo.setCreationTime(created);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
entry->setTimeInfo(timeInfo);
|
entry->setTimeInfo(timeInfo);
|
||||||
|
@ -96,21 +96,8 @@
|
|||||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QGridLayout" name="gridLayout_combos">
|
<layout class="QGridLayout" name="gridLayout_combos">
|
||||||
<item row="2" column="2">
|
<item row="3" column="1">
|
||||||
<widget class="QLabel" name="lastModifiedLabel">
|
<widget class="QComboBox" name="passwordCombo"/>
|
||||||
<property name="font">
|
|
||||||
<font>
|
|
||||||
<weight>50</weight>
|
|
||||||
<bold>false</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Last Modified</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QLabel" name="passwordLabel">
|
<widget class="QLabel" name="passwordLabel">
|
||||||
@ -126,13 +113,13 @@
|
|||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="indent">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1">
|
<item row="2" column="0">
|
||||||
<widget class="QComboBox" name="passwordCombo"/>
|
<widget class="QLabel" name="usernameLabel">
|
||||||
</item>
|
|
||||||
<item row="3" column="2">
|
|
||||||
<widget class="QLabel" name="createdLabel">
|
|
||||||
<property name="font">
|
<property name="font">
|
||||||
<font>
|
<font>
|
||||||
<weight>50</weight>
|
<weight>50</weight>
|
||||||
@ -140,28 +127,21 @@
|
|||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Created</string>
|
<string>Username</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="indent">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="2">
|
<item row="2" column="1">
|
||||||
<widget class="QLabel" name="notesLabel">
|
<widget class="QComboBox" name="usernameCombo"/>
|
||||||
<property name="font">
|
</item>
|
||||||
<font>
|
<item row="1" column="1">
|
||||||
<weight>50</weight>
|
<widget class="QComboBox" name="titleCombo"/>
|
||||||
<bold>false</bold>
|
|
||||||
</font>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>Notes</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QLabel" name="titleLabel">
|
<widget class="QLabel" name="titleLabel">
|
||||||
@ -177,6 +157,9 @@
|
|||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="indent">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
@ -196,9 +179,12 @@
|
|||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="indent">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="2">
|
<item row="4" column="0">
|
||||||
<widget class="QLabel" name="urlLabel">
|
<widget class="QLabel" name="urlLabel">
|
||||||
<property name="font">
|
<property name="font">
|
||||||
<font>
|
<font>
|
||||||
@ -212,10 +198,16 @@
|
|||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="indent">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="4" column="1">
|
||||||
<widget class="QLabel" name="usernameLabel">
|
<widget class="QComboBox" name="urlCombo"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QLabel" name="notesLabel">
|
||||||
<property name="font">
|
<property name="font">
|
||||||
<font>
|
<font>
|
||||||
<weight>50</weight>
|
<weight>50</weight>
|
||||||
@ -223,30 +215,106 @@
|
|||||||
</font>
|
</font>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Username</string>
|
<string>Notes</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="indent">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QComboBox" name="usernameCombo"/>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QComboBox" name="titleCombo"/>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="3">
|
<item row="0" column="3">
|
||||||
<widget class="QComboBox" name="urlCombo"/>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="3">
|
|
||||||
<widget class="QComboBox" name="notesCombo"/>
|
<widget class="QComboBox" name="notesCombo"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="3">
|
<item row="1" column="2">
|
||||||
<widget class="QComboBox" name="lastModifiedCombo"/>
|
<widget class="QLabel" name="totpLabel">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>TOTP</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="indent">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="3">
|
||||||
|
<widget class="QComboBox" name="totpCombo"/>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="3">
|
||||||
|
<widget class="QComboBox" name="createdCombo"/>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="2">
|
||||||
|
<widget class="QLabel" name="createdLabel">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Created</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="indent">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="2">
|
||||||
|
<widget class="QLabel" name="lastModifiedLabel">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Last Modified</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="indent">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="3">
|
<item row="3" column="3">
|
||||||
<widget class="QComboBox" name="createdCombo"/>
|
<widget class="QComboBox" name="lastModifiedCombo"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<widget class="QLabel" name="iconLabel">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>50</weight>
|
||||||
|
<bold>false</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Icon</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="indent">
|
||||||
|
<number>2</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="3">
|
||||||
|
<widget class="QComboBox" name="iconCombo"/>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
@ -682,10 +750,6 @@
|
|||||||
<tabstop>titleCombo</tabstop>
|
<tabstop>titleCombo</tabstop>
|
||||||
<tabstop>usernameCombo</tabstop>
|
<tabstop>usernameCombo</tabstop>
|
||||||
<tabstop>passwordCombo</tabstop>
|
<tabstop>passwordCombo</tabstop>
|
||||||
<tabstop>urlCombo</tabstop>
|
|
||||||
<tabstop>notesCombo</tabstop>
|
|
||||||
<tabstop>lastModifiedCombo</tabstop>
|
|
||||||
<tabstop>createdCombo</tabstop>
|
|
||||||
<tabstop>comboBoxCodec</tabstop>
|
<tabstop>comboBoxCodec</tabstop>
|
||||||
<tabstop>comboBoxTextQualifier</tabstop>
|
<tabstop>comboBoxTextQualifier</tabstop>
|
||||||
<tabstop>comboBoxFieldSeparator</tabstop>
|
<tabstop>comboBoxFieldSeparator</tabstop>
|
||||||
|
@ -928,10 +928,10 @@ void TestCli::testExport()
|
|||||||
setInput("a");
|
setInput("a");
|
||||||
execCmd(exportCmd, {"export", "-f", "csv", m_dbFile->fileName()});
|
execCmd(exportCmd, {"export", "-f", "csv", m_dbFile->fileName()});
|
||||||
QByteArray csvHeader = m_stdout->readLine();
|
QByteArray csvHeader = m_stdout->readLine();
|
||||||
QCOMPARE(csvHeader, QByteArray("\"Group\",\"Title\",\"Username\",\"Password\",\"URL\",\"Notes\"\n"));
|
QVERIFY(csvHeader.contains(QByteArray("\"Group\",\"Title\",\"Username\",\"Password\",\"URL\",\"Notes\"")));
|
||||||
QByteArray csvData = m_stdout->readAll();
|
QByteArray csvData = m_stdout->readAll();
|
||||||
QVERIFY(csvData.contains(QByteArray(
|
QVERIFY(csvData.contains(QByteArray(
|
||||||
"\"NewDatabase\",\"Sample Entry\",\"User Name\",\"Password\",\"http://www.somesite.com/\",\"Notes\"\n")));
|
"\"NewDatabase\",\"Sample Entry\",\"User Name\",\"Password\",\"http://www.somesite.com/\",\"Notes\"")));
|
||||||
|
|
||||||
// test invalid format
|
// test invalid format
|
||||||
setInput("a");
|
setInput("a");
|
||||||
|
@ -23,11 +23,13 @@
|
|||||||
|
|
||||||
#include "crypto/Crypto.h"
|
#include "crypto/Crypto.h"
|
||||||
#include "format/CsvExporter.h"
|
#include "format/CsvExporter.h"
|
||||||
|
#include "totp/totp.h"
|
||||||
|
|
||||||
QTEST_GUILESS_MAIN(TestCsvExporter)
|
QTEST_GUILESS_MAIN(TestCsvExporter)
|
||||||
|
|
||||||
const QString TestCsvExporter::ExpectedHeaderLine =
|
const QString TestCsvExporter::ExpectedHeaderLine =
|
||||||
QString("\"Group\",\"Title\",\"Username\",\"Password\",\"URL\",\"Notes\"\n");
|
QString("\"Group\",\"Title\",\"Username\",\"Password\",\"URL\",\"Notes\",\"TOTP\",\"Icon\",\"Last "
|
||||||
|
"Modified\",\"Created\"\n");
|
||||||
|
|
||||||
void TestCsvExporter::init()
|
void TestCsvExporter::init()
|
||||||
{
|
{
|
||||||
@ -57,17 +59,23 @@ void TestCsvExporter::testExport()
|
|||||||
entry->setPassword("Test Password");
|
entry->setPassword("Test Password");
|
||||||
entry->setUrl("http://test.url");
|
entry->setUrl("http://test.url");
|
||||||
entry->setNotes("Test Notes");
|
entry->setNotes("Test Notes");
|
||||||
|
entry->setTotp(Totp::createSettings("DFDF", Totp::DEFAULT_DIGITS, Totp::DEFAULT_STEP));
|
||||||
|
entry->setIcon(5);
|
||||||
|
|
||||||
QBuffer buffer;
|
QBuffer buffer;
|
||||||
QVERIFY(buffer.open(QIODevice::ReadWrite));
|
QVERIFY(buffer.open(QIODevice::ReadWrite));
|
||||||
m_csvExporter->exportDatabase(&buffer, m_db);
|
m_csvExporter->exportDatabase(&buffer, m_db);
|
||||||
|
auto exported = QString::fromUtf8(buffer.buffer());
|
||||||
|
|
||||||
QString expectedResult = QString()
|
QString expectedResult = QString()
|
||||||
.append(ExpectedHeaderLine)
|
.append(ExpectedHeaderLine)
|
||||||
.append("\"Passwords/Test Group Name\",\"Test Entry Title\",\"Test Username\",\"Test "
|
.append("\"Passwords/Test Group Name\",\"Test Entry Title\",\"Test Username\",\"Test "
|
||||||
"Password\",\"http://test.url\",\"Test Notes\"\n");
|
"Password\",\"http://test.url\",\"Test Notes\"");
|
||||||
|
|
||||||
QCOMPARE(QString::fromUtf8(buffer.buffer().constData()), expectedResult);
|
QVERIFY(exported.startsWith(expectedResult));
|
||||||
|
exported.remove(expectedResult);
|
||||||
|
QVERIFY(exported.contains("otpauth://"));
|
||||||
|
QVERIFY(exported.contains(",\"5\","));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestCsvExporter::testEmptyDatabase()
|
void TestCsvExporter::testEmptyDatabase()
|
||||||
@ -95,10 +103,9 @@ void TestCsvExporter::testNestedGroups()
|
|||||||
QBuffer buffer;
|
QBuffer buffer;
|
||||||
QVERIFY(buffer.open(QIODevice::ReadWrite));
|
QVERIFY(buffer.open(QIODevice::ReadWrite));
|
||||||
m_csvExporter->exportDatabase(&buffer, m_db);
|
m_csvExporter->exportDatabase(&buffer, m_db);
|
||||||
|
auto exported = QString::fromUtf8(buffer.buffer());
|
||||||
QCOMPARE(
|
QVERIFY(exported.startsWith(
|
||||||
QString::fromUtf8(buffer.buffer().constData()),
|
|
||||||
QString()
|
QString()
|
||||||
.append(ExpectedHeaderLine)
|
.append(ExpectedHeaderLine)
|
||||||
.append("\"Passwords/Test Group Name/Test Sub Group Name\",\"Test Entry Title\",\"\",\"\",\"\",\"\"\n"));
|
.append("\"Passwords/Test Group Name/Test Sub Group Name\",\"Test Entry Title\",\"\",\"\",\"\",\"\"")));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user