Skip to content

Commit

Permalink
Add option to modify SiVa URL and Certificate on settings page (open-…
Browse files Browse the repository at this point in the history
…eid#983)

IB-6839

Signed-off-by: Raul Metsma <[email protected]>

Signed-off-by: Raul Metsma <[email protected]>
  • Loading branch information
metsma authored Jan 5, 2023
1 parent 52de084 commit 07cf975
Show file tree
Hide file tree
Showing 8 changed files with 474 additions and 76 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ include( GNUInstallDirs )
include( VersionInfo )

find_package( PKCS11 )
find_package( LibDigiDocpp 3.14.8 REQUIRED )
find_package(LibDigiDocpp 3.14.11 REQUIRED)
find_package( LDAP REQUIRED )
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} 5.9.0 REQUIRED COMPONENTS Core Widgets Network PrintSupport Svg LinguistTools)
Expand Down
29 changes: 19 additions & 10 deletions client/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,17 @@ class DigidocConf final: public digidoc::XmlConfCurrent
{ SettingsDialog::setValueEx(QStringLiteral("TSA-URL"), QString::fromStdString(url)); }

std::string TSLUrl() const final { return valueSystemScope(QStringLiteral("TSL-URL"), digidoc::XmlConfCurrent::TSLUrl()); }
std::vector<digidoc::X509Cert> TSLCerts() const final
{
std::vector<digidoc::X509Cert> tslcerts;
for(const QJsonValue &val: obj.value(QStringLiteral("TSL-CERTS")).toArray())
{
QByteArray cert = QByteArray::fromBase64(val.toString().toLatin1());
tslcerts.emplace_back((const unsigned char*)cert.constData(), size_t(cert.size()));
}
return tslcerts.empty() ? digidoc::XmlConfCurrent::TSLCerts() : tslcerts;
}

digidoc::X509Cert verifyServiceCert() const final
{
QByteArray cert = QByteArray::fromBase64(obj.value(QStringLiteral("SIVA-CERT")).toString().toLatin1());
Expand All @@ -212,17 +223,15 @@ class DigidocConf final: public digidoc::XmlConfCurrent
}
return list;
}
std::string verifyServiceUri() const final { return valueSystemScope(QStringLiteral("SIVA-URL"), digidoc::XmlConfCurrent::verifyServiceUri()); }
std::vector<digidoc::X509Cert> TSLCerts() const final
std::string verifyServiceUri() const final
{
std::vector<digidoc::X509Cert> tslcerts;
for(const QJsonValue &val: obj.value(QStringLiteral("TSL-CERTS")).toArray())
{
QByteArray cert = QByteArray::fromBase64(val.toString().toLatin1());
tslcerts.emplace_back((const unsigned char*)cert.constData(), size_t(cert.size()));
}
return tslcerts.empty() ? digidoc::XmlConfCurrent::TSLCerts() : tslcerts;
if(s.value(QStringLiteral("SIVA-URL-CUSTOM"), s.contains(QStringLiteral("SIVA-URL"))).toBool())
return valueUserScope(QStringLiteral("SIVA-URL"), digidoc::XmlConfCurrent::verifyServiceUri());
return valueSystemScope(QStringLiteral("SIVA-URL"), digidoc::XmlConfCurrent::verifyServiceUri());
}
void setVerifyServiceUri(const std::string &url) final
{ SettingsDialog::setValueEx(QStringLiteral("SIVA-URL"), QString::fromStdString(url), QString()); }

std::string ocsp(const std::string &issuer) const final
{
QJsonObject ocspissuer = obj.value(QStringLiteral("OCSP-URL-ISSUER")).toObject();
Expand Down Expand Up @@ -1047,7 +1056,7 @@ void Application::setConfValue( ConfParameter parameter, const QVariant &value )
case PKCS12Disable: i->setPKCS12Disable( value.toBool() ); break;
case TSLOnlineDigest: i->setTSLOnlineDigest( value.toBool() ); break;
case TSAUrl: i->setTSUrl(v.isEmpty()? std::string() : v.constData()); break;
case SiVaUrl:
case SiVaUrl: i->setVerifyServiceUri(v.isEmpty()? std::string() : v.constData()); break;
case TSLCerts:
case TSLUrl:
case TSLCache: break;
Expand Down
136 changes: 113 additions & 23 deletions client/dialogs/SettingsDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ SettingsDialog::SettingsDialog(QWidget *parent)
ui->lblMenuSettings->setFont(headerFont);
ui->btnMenuGeneral->setFont(condensed12);
ui->btnMenuCertificate->setFont(condensed12);
ui->btnMenuValidation->setFont(condensed12);
ui->btnMenuProxy->setFont(condensed12);
ui->btnMenuDiagnostics->setFont(condensed12);
ui->btnMenuInfo->setFont(condensed12);
Expand Down Expand Up @@ -130,6 +131,21 @@ SettingsDialog::SettingsDialog(QWidget *parent)
ui->helpTimeStamp->installEventFilter(new ButtonHoverFilter(QStringLiteral(":/images/icon_Abi.svg"), QStringLiteral(":/images/icon_Abi_hover.svg"), this));
ui->helpMID->installEventFilter(new ButtonHoverFilter(QStringLiteral(":/images/icon_Abi.svg"), QStringLiteral(":/images/icon_Abi_hover.svg"), this));

// pageValidation
ui->lblSiVa->setFont(headerFont);
ui->lblSiVaCert->setFont(regularFont);
ui->txtSiVa->setFont(regularFont);
ui->txtSiVaCert->setFont(regularFont);
ui->rdSiVaDefault->setFont(regularFont);
ui->rdSiVaCustom->setFont(regularFont);
ui->btInstallSiVaCert->setFont(condensed12);
ui->btShowSiVaCert->setFont(condensed12);
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
ui->btInstallSiVaCert->setStyleSheet("background-color: #d3d3d3");
ui->btShowSiVaCert->setStyleSheet("background-color: #d3d3d3");
#endif
ui->helpSiVa->installEventFilter(new ButtonHoverFilter(QStringLiteral(":/images/icon_Abi.svg"), QStringLiteral(":/images/icon_Abi_hover.svg"), this));

// pageProxy
ui->rdProxyNone->setFont(regularFont);
ui->rdProxySystem->setFont(regularFont);
Expand Down Expand Up @@ -246,7 +262,8 @@ SettingsDialog::SettingsDialog(QWidget *parent)
#endif

ui->pageGroup->setId(ui->btnMenuGeneral, GeneralSettings);
ui->pageGroup->setId(ui->btnMenuCertificate, AccessCertSettings);
ui->pageGroup->setId(ui->btnMenuCertificate, SigningSettings);
ui->pageGroup->setId(ui->btnMenuValidation, ValidationSettings);
ui->pageGroup->setId(ui->btnMenuProxy, NetworkSettings);
ui->pageGroup->setId(ui->btnMenuDiagnostics, DiagnosticsSettings);
ui->pageGroup->setId(ui->btnMenuInfo, LicenseSettings);
Expand All @@ -269,6 +286,14 @@ SettingsDialog::~SettingsDialog()
delete ui;
}

QString SettingsDialog::certInfo(const SslCertificate &c)
{
return tr("Issued to: %1<br />Valid to: %2 %3").arg(
c.subjectInfo(QSslCertificate::CommonName),
c.expiryDate().toString(QStringLiteral("dd.MM.yyyy")),
!c.isValid() ? QStringLiteral("<font color='red'>(%1)</font>").arg(tr("expired")) : QString());
}

void SettingsDialog::checkConnection()
{
QApplication::setOverrideCursor( Qt::WaitCursor );
Expand Down Expand Up @@ -377,7 +402,7 @@ void SettingsDialog::initFunctionality()
ui->chkProxyEnableForSSL->setDisabled((s.value(QStringLiteral("ProxyConfig"), 0).toInt() != 2));
updateProxy();

// pageServices
// pageServices - Access Cert
updateCert();
connect(ui->btShowCertificate, &QPushButton::clicked, this, [this] {
CertificateDetails::showCertificate(SslCertificate(AccessCert::cert()), this);
Expand All @@ -387,7 +412,11 @@ void SettingsDialog::initFunctionality()
connect(ui->chkIgnoreAccessCert, &QCheckBox::toggled, this, [](bool checked) {
Application::setConfValue(Application::PKCS12Disable, checked);
});
connect(ui->helpRevocation, &QToolButton::clicked, this, []{
QDesktopServices::openUrl(tr("https://www.id.ee/en/article/access-certificate-what-is-it/"));
});

// pageServices - TimeStamp
connect(ui->rdTimeStampCustom, &QRadioButton::toggled, ui->txtTimeStamp, [=](bool checked) {
ui->txtTimeStamp->setEnabled(checked);
setValueEx(QStringLiteral("TSA-URL-CUSTOM"), checked, QSettings().contains(QStringLiteral("TSA-URL")));
Expand All @@ -401,6 +430,11 @@ void SettingsDialog::initFunctionality()
connect(ui->txtTimeStamp, &QLineEdit::textChanged, this, [](const QString &url) {
qApp->setConfValue(Application::TSAUrl, url);
});
connect(ui->helpTimeStamp, &QToolButton::clicked, this, []{
QDesktopServices::openUrl(tr("https://www.id.ee/en/article/for-organisations-that-sign-large-quantities-of-documents-using-digidoc4-client/"));
});

// pageServices - MID
connect(ui->rdMIDUUIDCustom, &QRadioButton::toggled, ui->txtMIDUUID, [=](bool checked) {
ui->txtMIDUUID->setEnabled(checked);
setValueEx(QStringLiteral("MIDUUID-CUSTOM"), checked, QSettings().contains(QStringLiteral("MIDUUID")));
Expand All @@ -412,16 +446,52 @@ void SettingsDialog::initFunctionality()
setValueEx(QStringLiteral("MIDUUID"), text);
setValueEx(QStringLiteral("SIDUUID"), text);
});
connect(ui->helpRevocation, &QToolButton::clicked, this, []{
QDesktopServices::openUrl(tr("https://www.id.ee/en/article/access-certificate-what-is-it/"));
});
connect(ui->helpTimeStamp, &QToolButton::clicked, this, []{
QDesktopServices::openUrl(tr("https://www.id.ee/en/article/for-organisations-that-sign-large-quantities-of-documents-using-digidoc4-client/"));
});
connect(ui->helpMID, &QToolButton::clicked, this, []{
QDesktopServices::openUrl(tr("https://www.id.ee/en/article/for-organisations-that-sign-large-quantities-of-documents-using-digidoc4-client/"));
});

// pageValidation - SiVa
connect(ui->rdSiVaCustom, &QRadioButton::toggled, ui->txtSiVa, [this](bool checked) {
ui->txtSiVa->setEnabled(checked);
ui->wgtSiVaCert->setVisible(checked);
setValueEx(QStringLiteral("SIVA-URL-CUSTOM"), checked, QSettings().contains(QStringLiteral("SIVA-URL")));
});
ui->rdSiVaCustom->setChecked(s.value(QStringLiteral("SIVA-URL-CUSTOM"), s.contains(QStringLiteral("SIVA-URL"))).toBool());
ui->wgtSiVaCert->setVisible(ui->rdSiVaCustom->isChecked());
#ifdef CONFIG_URL
ui->txtSiVa->setPlaceholderText(qApp->conf()->object().value(QStringLiteral("SIVA-URL")).toString());
#endif
QString SIVA_URL = s.value(QStringLiteral("SIVA-URL"), qApp->confValue(Application::SiVaUrl)).toString();
ui->txtSiVa->setText(ui->txtSiVa->placeholderText() == SIVA_URL ? QString() : SIVA_URL);
connect(ui->txtSiVa, &QLineEdit::textChanged, this, [this](const QString &url) {
qApp->setConfValue(Application::SiVaUrl, url);
if(url.isEmpty())
{
QSettings().remove(QStringLiteral("SIVA-CERT"));
updateSiVaCert(QSslCertificate());
}
});
connect(ui->helpSiVa, &QToolButton::clicked, this, []{
QDesktopServices::openUrl(tr("https://www.id.ee/en/article/configuring-the-siva-validation-service-in-the-digidoc4-client/"));
});
connect(ui->btInstallSiVaCert, &QPushButton::clicked, this, [this] {
QFile file(FileDialog::getOpenFileName(this, tr("Select SiVa server certificate"), {},
QStringLiteral("%1 (*.crt *.cer *.pem)")).arg(tr("Digital Signature Validation Service SiVa SSL certificate")));
if(!file.open(QFile::ReadOnly))
return;
QSslCertificate cert(&file, QSsl::Pem);
if(cert.isNull())
{
file.seek(0);
cert = QSslCertificate(&file, QSsl::Der);
}
if(cert.isNull())
return;
QSettings().setValue(QStringLiteral("SIVA-CERT"), cert.toDer().toBase64());
updateSiVaCert(cert);
});
updateSiVaCert(QSslCertificate(QByteArray::fromBase64(s.value(QStringLiteral("SIVA-CERT")).toByteArray()), QSsl::Der));

// pageDiagnostics
ui->chkLibdigidocppDebug->setChecked(s.value(QStringLiteral("LibdigidocppDebug"), false).toBool());
connect(ui->chkLibdigidocppDebug, &QCheckBox::toggled, this, [this](bool checked) {
Expand Down Expand Up @@ -453,21 +523,25 @@ void SettingsDialog::initFunctionality()
void SettingsDialog::updateCert()
{
QSslCertificate c = AccessCert::cert();
if( !c.isNull() )
{
ui->txtAccessCert->setText(
tr("Issued to: %1<br />Valid to: %2 %3").arg(
CertificateDetails::decodeCN(SslCertificate(c).subjectInfo(QSslCertificate::CommonName)),
c.expiryDate().toString(QStringLiteral("dd.MM.yyyy")),
!SslCertificate(c).isValid() ? "<font color='red'>(" + tr("expired") + ")</font>" : QString()));
}
if(!c.isNull())
ui->txtAccessCert->setText(certInfo(c));
else
{
ui->txtAccessCert->setText(
"<b>" + tr("Server access certificate is not installed.") + "</b>" );
}
ui->btShowCertificate->setEnabled(!c.isNull());
ui->btShowCertificate->setProperty("cert", QVariant::fromValue(c));
ui->txtAccessCert->setText(QStringLiteral("<b>%1</b>")
.arg(tr("Server access certificate is not installed.")));
ui->btShowCertificate->setDisabled(c.isNull());
}

void SettingsDialog::updateSiVaCert(const QSslCertificate &c)
{
disconnect(ui->btShowSiVaCert, &QPushButton::clicked, nullptr, nullptr);
ui->btShowSiVaCert->setHidden(c.isNull());
ui->txtSiVaCert->setHidden(c.isNull());
if(c.isNull())
return;
ui->txtSiVaCert->setCert(c);
connect(ui->btShowSiVaCert, &QPushButton::clicked, this, [this, c] {
CertificateDetails::showCertificate(c, this);
});
}

void SettingsDialog::selectLanguage()
Expand Down Expand Up @@ -608,6 +682,7 @@ void SettingsDialog::useDefaultSettings()
AccessCert().remove();
updateCert();
ui->rdTimeStampDefault->setChecked(true);
ui->rdSiVaDefault->setChecked(true);
ui->rdMIDUUIDDefault->setChecked(true);
}

Expand All @@ -620,7 +695,7 @@ void SettingsDialog::changePage(QAbstractButton *button)
{
button->setChecked(true);
ui->stackedWidget->setCurrentIndex(ui->pageGroup->id(button));
ui->btnNavUseByDefault->setVisible(button == ui->btnMenuCertificate);
ui->btnNavUseByDefault->setVisible(button == ui->btnMenuCertificate || button == ui->btnMenuValidation);
ui->btnFirstRun->setVisible(button == ui->btnMenuGeneral);
ui->btnRefreshConfig->setVisible(button == ui->btnMenuGeneral);
ui->btnCheckConnection->setVisible(button == ui->btnMenuProxy);
Expand Down Expand Up @@ -653,3 +728,18 @@ void SettingsDialog::saveFile(const QString &name, const QByteArray &content)
if(!f.open(QIODevice::WriteOnly|QIODevice::Text) || !f.write(content))
WarningDialog::show(this, tr("Failed write to file!"));
}



void CertLabel::setCert(const QSslCertificate &cert)
{
setText(SettingsDialog::certInfo(cert));
setProperty("cert", QVariant::fromValue(cert));
}

bool CertLabel::event(QEvent *event)
{
if(event->type() == QEvent::LanguageChange)
setText(SettingsDialog::certInfo(property("cert").value<QSslCertificate>()));
return QLabel::event(event);
}
17 changes: 16 additions & 1 deletion client/dialogs/SettingsDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <QDialog>

#include <QLabel>
#include <QVariant>

namespace digidoc { class Conf; }
Expand All @@ -30,6 +31,8 @@ class SettingsDialog;
}

class QAbstractButton;
class QSslCertificate;
class SslCertificate;

class SettingsDialog final: public QDialog
{
Expand All @@ -38,7 +41,8 @@ class SettingsDialog final: public QDialog
public:
enum {
GeneralSettings,
AccessCertSettings,
SigningSettings,
ValidationSettings,
NetworkSettings,
DiagnosticsSettings,
LicenseSettings
Expand All @@ -49,6 +53,7 @@ class SettingsDialog final: public QDialog
~SettingsDialog() final;

void showPage(int page);
static QString certInfo(const SslCertificate &c);
static void loadProxy( const digidoc::Conf *conf );
static void setValueEx(const QString &key, const QVariant &value, const QVariant &def = {});

Expand All @@ -68,10 +73,20 @@ class SettingsDialog final: public QDialog
void selectLanguage();
void setProxyEnabled();
void updateCert();
void updateSiVaCert(const QSslCertificate &c);
void updateProxy();
void updateVersion();
void updateDiagnostics();
void useDefaultSettings();

Ui::SettingsDialog *ui;
};

class CertLabel final: public QLabel {
Q_OBJECT
public:
using QLabel::QLabel;
void setCert(const QSslCertificate &cert);
private:
bool event(QEvent *event) final;
};
Loading

0 comments on commit 07cf975

Please sign in to comment.