aheinecke@404: /* Copyright (C) 2014 by Bundesamt für Sicherheit in der Informationstechnik aheinecke@404: * Software engineering by Intevation GmbH aheinecke@404: * aheinecke@404: * This file is Free Software under the GNU GPL (v>=2) aheinecke@404: * and comes with ABSOLUTELY NO WARRANTY! aheinecke@404: * See LICENSE.txt for details. aheinecke@404: */ rrenkert@333: #include "administratorwindow.h" rrenkert@333: rrenkert@333: #include rrenkert@333: #include rrenkert@333: #include rrenkert@333: #include rrenkert@333: #include rrenkert@333: #include rrenkert@333: #include rrenkert@333: #include rrenkert@333: #include rrenkert@333: #include rrenkert@333: #include rrenkert@333: #include rrenkert@335: #include rrenkert@344: #include rrenkert@394: #include rrenkert@398: #include andre@1001: #include andre@1001: #include rrenkert@333: rrenkert@348: #include "certificatetabledelegate.h" rrenkert@362: #include "createinstallerdialog.h" rrenkert@368: #include "createcertlistdialog.h" rrenkert@566: #include "certificatediffdialog.h" rrenkert@427: #include "aboutdialog.h" andre@1001: #include "util.h" andre@1001: andre@1001: #define HELP_PATH "/doc/index.html" rrenkert@348: rrenkert@333: AdministratorWindow::AdministratorWindow() { rrenkert@412: setWindowTitle(tr("TrustBridge Administration")); rrenkert@333: createActions(); rrenkert@333: createMenuBar(); rrenkert@333: createContent(); andre@1317: loadCurrentCertificates(); andre@1317: resize(1190, 500); andre@1317: } andre@1317: andre@1317: void AdministratorWindow::loadCurrentCertificates() andre@1317: { andre@1317: QString path = QStandardPaths::locate( andre@1317: QStandardPaths::DataLocation, QString("current_certificates.txt")); andre@1317: certificateModel->removeAll(); andre@1317: mCertList.readList(path.toLocal8Bit()); rrenkert@394: loadCertificateTable(); rrenkert@333: } rrenkert@333: rrenkert@333: void AdministratorWindow::createActions() rrenkert@333: { rrenkert@333: } rrenkert@333: rrenkert@333: void AdministratorWindow::createMenuBar() rrenkert@333: { rrenkert@333: menuBar = new QMenuBar(this); rrenkert@333: QMenu *menu = new QMenu(tr("Menu"), menuBar); rrenkert@333: menuBar->addMenu(menu); rrenkert@415: QAction *createInstaller = menu->addAction(tr("Create installer ...")); rrenkert@415: QAction *about = menu->addAction(tr("About TrustBridge")); andre@1001: QAction *help = menu->addAction(tr("Help")); andre@1001: help->setIcon(QIcon(":/img/show-help_16.png")); rrenkert@333: menu->addSeparator(); rrenkert@333: QAction *quit = menu->addAction(tr("Quit")); rrenkert@333: connect(createInstaller, SIGNAL(triggered()), this, SLOT(createInstaller())); rrenkert@333: connect(about, SIGNAL(triggered()), this, SLOT(showAbout())); andre@1001: connect(help, SIGNAL(triggered()), this, SLOT(showHelp())); rrenkert@333: connect(quit, SIGNAL(triggered()), qApp, SLOT(quit())); rrenkert@333: setMenuBar(menuBar); rrenkert@333: } rrenkert@333: rrenkert@333: void AdministratorWindow::createContent() rrenkert@333: { rrenkert@333: // Create a central widget containing the main layout. rrenkert@333: QWidget *base = new QWidget; rrenkert@333: rrenkert@333: // Layouts and Container rrenkert@333: QVBoxLayout *mainLayout = new QVBoxLayout; rrenkert@333: QVBoxLayout *certLayout = new QVBoxLayout; rrenkert@333: QHBoxLayout *headerLayout = new QHBoxLayout; rrenkert@333: QVBoxLayout *headerTextLayout = new QVBoxLayout; rrenkert@333: QHBoxLayout *bottomLayout = new QHBoxLayout; rrenkert@333: rrenkert@333: // The certificate list rrenkert@412: QGroupBox *certBox = new QGroupBox( rrenkert@426: tr("All managed root certificates of the certificate list: ")); rrenkert@335: certificateView = new QTableView; rrenkert@343: certificateModel = new CertificateTabelModel(); andre@1316: mFilterModel = new QSortFilterProxyModel(this); andre@1316: mFilterModel->setSourceModel(certificateModel); rrenkert@348: CertificateTableDelegate *delegate = new CertificateTableDelegate(certificateView); andre@1316: certificateView->setModel(mFilterModel); rrenkert@348: certificateView->setItemDelegate(delegate); rrenkert@426: certificateView->horizontalHeader()->setStretchLastSection(true); rrenkert@395: certificateView->resizeColumnsToContents(); rrenkert@395: certificateView->setColumnWidth(0, 60); rrenkert@343: certificateView->setSelectionBehavior(QAbstractItemView::SelectRows); andre@1323: certificateView->setSelectionMode(QAbstractItemView::SingleSelection); rrenkert@376: connect(certificateView, SIGNAL(clicked(const QModelIndex&)), this, rrenkert@376: SLOT(clickedCertificate(const QModelIndex&))); rrenkert@343: certificateView->verticalHeader()->setVisible(false); rrenkert@398: certificateView->setSortingEnabled(true); rrenkert@335: certLayout->addWidget(certificateView); rrenkert@333: certBox->setLayout(certLayout); rrenkert@333: rrenkert@333: // The header (icon, about text) rrenkert@333: QImage *logoImage = new QImage(":/img/logo.png"); rrenkert@333: QLabel *logo = new QLabel; rrenkert@333: logo->setBackgroundRole(QPalette::Base); rrenkert@333: logo->setPixmap(QPixmap::fromImage(*logoImage)); rrenkert@427: QLabel *title = new QLabel("

" + tr("TrustBridge Administration") + "

"); rrenkert@412: QLabel *subTitle = new QLabel( rrenkert@412: tr("Management application of the BSI certificate installer")); rrenkert@333: headerTextLayout->addWidget(title); rrenkert@333: headerTextLayout->addWidget(subTitle); rrenkert@333: headerLayout->addWidget(logo); rrenkert@333: headerLayout->addLayout(headerTextLayout); rrenkert@333: headerLayout->setStretch(0, 0); rrenkert@333: headerLayout->setStretch(1, 10); rrenkert@333: rrenkert@333: // The buttons. rrenkert@333: bottomLayout->setAlignment(Qt::AlignBottom); emanuel@1274: saveButton = new QPushButton(QIcon(":/img/document-save.png"), " " + tr("Create list")); rrenkert@368: connect(saveButton, SIGNAL(clicked()), this, SLOT(saveCertificateFile())); emanuel@1199: loadButton = new QPushButton(QIcon(":/img/document-open.png"), " " + tr("Load list")); rrenkert@344: connect(loadButton, SIGNAL(clicked()), this, SLOT(loadCertificateFile())); emanuel@1199: addButton = new QPushButton(QIcon(":/img/document-new.png"), " " + tr("Add certificate")); rrenkert@358: connect(addButton, SIGNAL(clicked()), this, SLOT(addCertificates())); emanuel@1199: removeButton = new QPushButton(QIcon(":/img/document-close.png"), " " + tr("Remove certificate")); rrenkert@376: removeButton->setEnabled(false); rrenkert@376: connect(removeButton, SIGNAL(clicked()), this, SLOT(removeCertificates())); rrenkert@333: bottomLayout->addWidget(saveButton); rrenkert@333: bottomLayout->addWidget(loadButton); rrenkert@333: bottomLayout->addWidget(addButton); rrenkert@333: bottomLayout->addWidget(removeButton); rrenkert@333: bottomLayout->insertStretch(4, 10); rrenkert@333: rrenkert@333: mainLayout->addLayout(headerLayout); rrenkert@333: mainLayout->addWidget(certBox); rrenkert@333: mainLayout->addLayout(bottomLayout); rrenkert@333: rrenkert@333: rrenkert@333: // QMainWindow allready has a layout. All child layouts and widgets are rrenkert@333: // managed in the central widget. rrenkert@333: base->setLayout(mainLayout); rrenkert@333: setCentralWidget(base); rrenkert@333: } rrenkert@333: rrenkert@344: void AdministratorWindow::loadCertificateFile() rrenkert@344: { aheinecke@515: QString lastCertFile = mSettings.value("LastCertList", QDir::homePath()).toString(); rrenkert@344: QString certFile = QFileDialog::getOpenFileName( aheinecke@515: this, tr("Select certificate list file"), lastCertFile, "*.txt"); rrenkert@567: if (certFile.isNull()) { rrenkert@567: return; rrenkert@567: } aheinecke@453: mCertList.readList(certFile.toLocal8Bit().constData()); aheinecke@453: if (!mCertList.isValid()) { aheinecke@515: QMessageBox::warning(this, tr("Error!"), tr("Failed to load the certificate list.")); aheinecke@462: } else { rrenkert@396: certificateModel->removeAll(); rrenkert@344: loadCertificateTable(); aheinecke@515: mSettings.setValue("LastCertList", certFile); rrenkert@344: } rrenkert@344: } rrenkert@344: rrenkert@368: void AdministratorWindow::saveCertificateFile() rrenkert@368: { rrenkert@566: CertificateDiffDialog *diffDialog = new CertificateDiffDialog(this); rrenkert@566: int ret = diffDialog->exec(); rrenkert@566: if (ret == QDialog::Accepted) { rrenkert@566: CreateCertListDialog *dialog = new CreateCertListDialog(this); rrenkert@566: dialog->show(); andre@1317: connect (dialog, SIGNAL(creationSuccessful()), this, SLOT(loadCurrentCertificates())); rrenkert@566: } rrenkert@368: } rrenkert@368: rrenkert@358: void AdministratorWindow::addCertificates() rrenkert@358: { rrenkert@429: QStringList certFiles = QFileDialog::getOpenFileNames( andre@1324: this, tr("Select certificate"), mSettings.value("LastCertAddDir", QDir::homePath()).toString(), andre@1324: "*.pem *.der *.crt *.cer"); rrenkert@429: for (int i = 0; i < certFiles.size(); i++) { rrenkert@429: QString certFile = certFiles.at(i); rrenkert@429: QList certs = Certificate::fromFileName(certFile); rrenkert@429: addToCertificateTable(certs); andre@1324: QDir certDir (certFile); andre@1324: mSettings.setValue("LastCertAddDir", certDir.absolutePath()); rrenkert@429: } rrenkert@427: certificateView->resizeColumnsToContents(); rrenkert@427: certificateView->setColumnWidth(0, 60); rrenkert@358: } rrenkert@358: rrenkert@376: void AdministratorWindow::removeCertificates() rrenkert@376: { rrenkert@376: QModelIndexList list = certificateView->selectionModel()->selectedRows(); andre@1316: foreach (QModelIndex idx, list) { andre@1316: QModelIndex realidx = mFilterModel->mapToSource(idx); andre@1318: if (!idx.data(Qt::UserRole).toBool()) { andre@1316: certificateModel->removeRow(realidx.row(), realidx.parent()); andre@1316: } else { andre@1316: qDebug() << "Tried to remove old certificate at idx: " << realidx.row();; andre@1316: } rrenkert@376: } rrenkert@376: } rrenkert@376: rrenkert@344: void AdministratorWindow::loadCertificateTable() { aheinecke@453: foreach(const Certificate &cert, mCertList.getCertificates()) { rrenkert@358: certificateModel->addCertificate(cert, true); rrenkert@358: } rrenkert@395: certificateView->resizeColumnsToContents(); rrenkert@395: certificateView->setColumnWidth(0, 60); rrenkert@358: } rrenkert@358: rrenkert@358: void AdministratorWindow::addToCertificateTable(const QList &certs) rrenkert@358: { rrenkert@358: foreach(const Certificate &cert, certs) { rrenkert@358: certificateModel->addCertificate(cert, false); rrenkert@344: } rrenkert@344: } rrenkert@344: rrenkert@333: void AdministratorWindow::showAbout() rrenkert@333: { rrenkert@427: AboutDialog *dialog = new AboutDialog(this); rrenkert@427: dialog->show(); rrenkert@333: } rrenkert@333: rrenkert@333: void AdministratorWindow::createInstaller() rrenkert@333: { rrenkert@333: qDebug() << "create Installer"; rrenkert@362: CreateInstallerDialog *dialog = new CreateInstallerDialog(this); rrenkert@362: dialog->show(); rrenkert@333: } rrenkert@333: rrenkert@376: void AdministratorWindow::clickedCertificate(const QModelIndex &index) rrenkert@376: { andre@1318: QModelIndexList list = certificateView->selectionModel()->selectedRows(); andre@1318: bool all_are_removable = true; andre@1318: foreach (QModelIndex idx, list) { andre@1318: if (idx.data(Qt::UserRole).toBool()) { andre@1318: all_are_removable = false; andre@1318: break; andre@1318: } rrenkert@376: } andre@1318: removeButton->setEnabled(all_are_removable); rrenkert@376: } rrenkert@562: andre@679: void AdministratorWindow::logChanges(const QString ¤tCerts, const QString& keyFingerprint) rrenkert@562: { rrenkert@562: QDir logDir(QStandardPaths::writableLocation(QStandardPaths::DataLocation)); rrenkert@562: QString logFilePath = logDir.filePath("log.txt"); rrenkert@562: QFile logFile(logFilePath); rrenkert@562: rrenkert@562: if (!logFile.open(QIODevice::Append)) { aheinecke@570: QMessageBox::warning(this, tr("Error!"), tr("Failed to open log file: ") + aheinecke@570: logFilePath + tr(" Changes are not logged!")); rrenkert@562: qDebug() << "Failed to open log file: " << logFilePath; rrenkert@562: return; rrenkert@562: } rrenkert@562: rrenkert@562: CertificateList newCertList; rrenkert@562: newCertList.readList(currentCerts.toLocal8Bit()); andre@679: QByteArray entries = createLogEntries(newCertList, keyFingerprint); rrenkert@562: if(logFile.write(entries) != entries.size()) { aheinecke@570: QMessageBox::warning(this, tr("Error!"), tr("Failed to write log file: ") + aheinecke@570: logFilePath + tr(" Changes are not logged!")); rrenkert@562: return; rrenkert@562: } rrenkert@562: logFile.close(); rrenkert@562: } rrenkert@562: andre@679: QByteArray AdministratorWindow::createLogEntries(const CertificateList &list, const QString& keyFingerprint) rrenkert@562: { rrenkert@562: QByteArray entries; rrenkert@562: QByteArray removeListEntries; rrenkert@562: rrenkert@562: QDateTime currentDate = QDateTime::currentDateTime(); rrenkert@562: QDateTime newListDate = list.date(); rrenkert@562: QDateTime listDate = mCertList.date(); rrenkert@562: rrenkert@562: entries.append("##### " + rrenkert@562: currentDate.toString("yyyy-MM-dd hh:mm") + rrenkert@562: tr(" new certificatelist ") + rrenkert@562: newListDate.toString(Qt::ISODate) + rrenkert@562: tr(" based on list from ") + rrenkert@562: listDate.toString(Qt::ISODate) + rrenkert@562: "#####\r\n"); andre@1283: entries.append(tr("signing certificate:") + "\r\n"); andre@679: entries.append(keyFingerprint); andre@679: andre@1283: entries.append(QString::fromLatin1("\r\n") + tr("new certificates:") +"\r\n"); rrenkert@562: rrenkert@562: foreach (const Certificate& cert, list.getCertificates()) { rrenkert@562: if (!mCertList.getCertificates().contains(cert)) { rrenkert@562: QString certEntry(cert.subjectCN() + ": " + cert.base64Line() + "\r\n"); rrenkert@562: if (cert.isInstallCert()) { rrenkert@562: entries.append(certEntry); rrenkert@562: } rrenkert@562: else { rrenkert@562: removeListEntries.append(certEntry); rrenkert@562: } rrenkert@562: } rrenkert@562: } rrenkert@562: andre@1283: entries.append(tr("certificates marked to remove:") + "\r\n"); rrenkert@562: entries.append(removeListEntries); rrenkert@562: entries.append("\r\n"); rrenkert@562: rrenkert@562: return entries; rrenkert@562: } rrenkert@565: rrenkert@565: QList AdministratorWindow::currentChanges() rrenkert@565: { rrenkert@565: QList changed; rrenkert@565: foreach(const Certificate& cert, certificates()) { rrenkert@565: if (!mCertList.getCertificates().contains(cert)) { rrenkert@565: changed.append(cert); rrenkert@565: } rrenkert@565: } rrenkert@565: return changed; rrenkert@565: } andre@1001: andre@1001: void AdministratorWindow::showHelp() andre@1001: { andre@1001: char *inst_dir = get_install_dir(); andre@1001: if (!inst_dir) { andre@1001: qDebug() << "Failed to find install dir"; andre@1001: return; andre@1001: } andre@1001: QString helpPath = QString::fromUtf8(inst_dir); andre@1001: helpPath += HELP_PATH; andre@1001: QFileInfo fiHelp(helpPath); andre@1001: qDebug() << "Opening help: " << fiHelp.absoluteFilePath(); andre@1001: if (!fiHelp.exists()) { andre@1001: QMessageBox::warning(this, tr("Error!"), tr ("Failed to find the manual")); andre@1001: return; andre@1001: } andre@1001: #ifdef Q_OS_WIN andre@1001: QDesktopServices::openUrl(QUrl("file:///" + fiHelp.absoluteFilePath())); andre@1001: #else andre@1001: QDesktopServices::openUrl(QUrl(fiHelp.absoluteFilePath())); andre@1001: #endif andre@1001: free (inst_dir); andre@1001: return; andre@1001: }