Merge pull request #2582 from csoler/v0.6-FriendServer2

Improving the logic of certificate handling UI
This commit is contained in:
csoler 2022-02-16 00:22:12 +01:00 committed by GitHub
commit 3dfcb58ae1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 169 additions and 135 deletions

@ -1 +1 @@
Subproject commit 5a6f09ee11a34f1c52b5be3f0a440f185b9b2a89
Subproject commit 87fdae942186ab3412ce40438e30f76670dd55d0

View File

@ -229,7 +229,7 @@ void GetStartedDialog::inviteFriends()
{
RsAutoUpdatePage::lockAllEvents();
cert = rsPeers->GetRetroshareInvite(RsPeerId(),RetroshareInviteFlags::DNS | RetroshareInviteFlags::CURRENT_IP | RetroshareInviteFlags::FULL_IP_HISTORY);
cert = rsPeers->GetRetroshareInvite(RsPeerId(),RsPeers::defaultCertificateFlags | RetroshareInviteFlags::FULL_IP_HISTORY);
RsAutoUpdatePage::unlockAllEvents() ;
}

View File

@ -50,14 +50,10 @@
HomePage::HomePage(QWidget *parent) :
MainPage(parent),
ui(new Ui::HomePage),
mIncludeAllIPs(false),
mUseShortFormat(true)
ui(new Ui::HomePage)
{
ui->setupUi(this);
updateCertificate();
connect(ui->addButton, SIGNAL(clicked()), this, SLOT(addFriend()));
connect(ui->copyIDButton, SIGNAL(clicked()), this, SLOT(copyId()));
@ -73,29 +69,48 @@ HomePage::HomePage(QWidget *parent) :
QAction *CopyIdAction = new QAction(QIcon(),tr("Copy your Retroshare ID to Clipboard"), this);
connect(CopyIdAction, SIGNAL(triggered()), this, SLOT(copyId()));
QMenu *menu = new QMenu();
QMenu *menu = new QMenu();
menu->addAction(CopyIdAction);
if(!RsAccounts::isHiddenNode())
{
QAction *includeIPsAct = new QAction(QIcon(), tr("Include all your known IPs"),this);
connect(includeIPsAct, SIGNAL(triggered()), this, SLOT(toggleIncludeAllIPs()));
includeIPsAct->setCheckable(true);
includeIPsAct->setChecked(mIncludeAllIPs);
menu->addAction(includeIPsAct);
}
QAction *useOldFormatAct = new QAction(QIcon(), tr("Use old certificate format"),this);
useOldFormatAct->setToolTip(tr("Displays the certificate format used up to version 0.6.5\nOld Retroshare nodes will not understand the\nnew short format"));
connect(useOldFormatAct, SIGNAL(triggered()), this, SLOT(toggleUseOldFormat()));
useOldFormatAct->setCheckable(true);
useOldFormatAct->setChecked(!mUseShortFormat);
menu->addAction(useOldFormatAct);
menu->addSeparator();
menu->addAction(SendAction);
menu->addAction(WebMailAction);
menu->addAction(RecAction);
menu->addSeparator();
mUseOldFormatact = new QAction(QIcon(), tr("Use old certificate format"),this);
mUseOldFormatact->setToolTip(tr("Displays the certificate format used up to version 0.6.5\nOld Retroshare nodes will not understand the\nnew short format"));
connect(mUseOldFormatact, SIGNAL(triggered()), this, SLOT(updateOwnCert()));
mUseOldFormatact->setCheckable(true);
mUseOldFormatact->setChecked(false);
menu->addAction(mUseOldFormatact);
if(!RsAccounts::isHiddenNode())
{
mIncludeLocIPact = new QAction(QIcon(), tr("Include current local IP"),this);
connect(mIncludeLocIPact, SIGNAL(triggered()), this, SLOT(updateOwnCert()));
mIncludeLocIPact->setCheckable(true);
mIncludeLocIPact->setChecked(true);
menu->addAction(mIncludeLocIPact);
mIncludeExtIPact = new QAction(QIcon(), tr("Include current external IP"),this);
connect(mIncludeExtIPact, SIGNAL(triggered()), this, SLOT(updateOwnCert()));
mIncludeExtIPact->setCheckable(true);
mIncludeExtIPact->setChecked(true);
menu->addAction(mIncludeExtIPact);
mIncludeDNSact = new QAction(QIcon(), tr("Include my DNS"),this);
connect(mIncludeDNSact, SIGNAL(triggered()), this, SLOT(updateOwnCert()));
mIncludeDNSact->setCheckable(true);
mIncludeDNSact->setChecked(true);
menu->addAction(mIncludeDNSact);
mIncludeIPHistoryact = new QAction(QIcon(), tr("Include all IPs history"),this);
connect(mIncludeIPHistoryact, SIGNAL(triggered()), this, SLOT(updateOwnCert()));
mIncludeIPHistoryact->setCheckable(true);
mIncludeIPHistoryact->setChecked(false);
menu->addAction(mIncludeIPHistoryact);
}
ui->shareButton->setMenu(menu);
@ -118,6 +133,8 @@ HomePage::HomePage(QWidget *parent) :
mEventHandlerId = 0;
rsEvents->registerEventsHandler( [this](std::shared_ptr<const RsEvent> event) { handleEvent(event); }, mEventHandlerId, RsEventType::NETWORK );
updateOwnCert();
}
void HomePage::handleEvent(std::shared_ptr<const RsEvent> e)
@ -139,13 +156,15 @@ void HomePage::handleEvent(std::shared_ptr<const RsEvent> e)
case RsNetworkEventCode::DNS_UPDATED: // [fallthrough]
RsQThreadUtils::postToObject( [=]()
{
updateCertificate();
updateOwnCert();
},this);
break;
default:
break;
}
}
#ifdef DEAD_CODE
void HomePage::certContextMenu(QPoint /*point*/)
{
QMenu menu(this) ;
@ -178,17 +197,7 @@ void HomePage::certContextMenu(QPoint /*point*/)
menu.exec(QCursor::pos());
}
void HomePage::toggleUseShortFormat()
{
mUseShortFormat = !mUseShortFormat;
updateCertificate();
}
void HomePage::toggleIncludeAllIPs()
{
mIncludeAllIPs = !mIncludeAllIPs;
updateCertificate();
}
#endif
HomePage::~HomePage()
{
@ -196,15 +205,8 @@ HomePage::~HomePage()
delete ui;
}
void HomePage::updateCertificate()
void HomePage::getOwnCert(QString& invite,QString& description) const
{
updateOwnCert();
}
void HomePage::updateOwnCert()
{
bool include_extra_locators = mIncludeAllIPs;
RsPeerDetails detail;
if (!rsPeers->getPeerDetails(rsPeers->getOwnId(), detail))
@ -213,23 +215,46 @@ void HomePage::updateOwnCert()
return ;
}
QString invite ;
RetroshareInviteFlags invite_flags = RetroshareInviteFlags::CURRENT_IP | RetroshareInviteFlags::DNS;
RetroshareInviteFlags invite_flags = RetroshareInviteFlags::NOTHING;
if(mIncludeAllIPs)
if(mIncludeLocIPact->isChecked())
invite_flags |= RetroshareInviteFlags::CURRENT_LOCAL_IP;
if(mIncludeExtIPact->isChecked())
invite_flags |= RetroshareInviteFlags::CURRENT_EXTERNAL_IP;
if(mIncludeDNSact->isChecked())
invite_flags |= RetroshareInviteFlags::DNS;
if(mIncludeIPHistoryact->isChecked())
invite_flags |= RetroshareInviteFlags::FULL_IP_HISTORY;
if(mUseShortFormat)
if(!mUseOldFormatact->isChecked())
{
std::string short_invite;
rsPeers->getShortInvite(short_invite,rsPeers->getOwnId(),invite_flags | RetroshareInviteFlags::RADIX_FORMAT);
invite = QString::fromStdString(short_invite);
}
else
invite = QString::fromStdString(rsPeers->GetRetroshareInvite(detail.id,invite_flags));
description = ConfCertDialog::getCertificateDescription(detail,false,!mUseOldFormatact->isChecked(),invite_flags);
}
void HomePage::updateOwnCert()
{
QString certificate, description;
getOwnCert(certificate,description);
if(!mUseOldFormatact->isChecked()) // in this case we have to split the cert for a better display
{
QString S;
QString txt;
for(uint32_t i=0;i<short_invite.size();)
for(int i=0;i<certificate.size();)
if(S.length() < 100)
S += short_invite[i++];
S += certificate[i++];
else
{
txt += S + "\n";
@ -237,16 +262,10 @@ void HomePage::updateOwnCert()
}
txt += S;
invite = txt; // the "\n" is here to make some space
certificate = txt; // the "\n" is here to make some space
}
else
invite = QString::fromStdString(rsPeers->GetRetroshareInvite(detail.id,invite_flags));
ui->retroshareid->setText("\n"+invite+"\n");
QString description = ConfCertDialog::getCertificateDescription(detail,false,mUseShortFormat,include_extra_locators);
ui->retroshareid->setText("\n"+certificate+"\n");
ui->retroshareid->setToolTip(description);
}
@ -348,9 +367,3 @@ void HomePage::openWebHelp()
{
QDesktopServices::openUrl(QUrl(QString("https://retrosharedocs.readthedocs.io/en/latest/")));
}
void HomePage::toggleUseOldFormat()
{
mUseShortFormat = !mUseShortFormat;
updateCertificate();
}

View File

@ -46,28 +46,32 @@ public:
virtual QString pageName() const { return tr("Home") ; } //MainPage
virtual QString helpText() const { return ""; } //MainPage
// Returns the certificate along with its description using current options.
void getOwnCert(QString& invite,QString& description) const;
private slots:
void certContextMenu(QPoint);
#ifdef DEAD_CODE
void certContextMenu(QPoint);
#endif
void updateOwnCert();
void updateCertificate();
void runEmailClient();
void copyCert();
void copyId();
void saveCert();
void addFriend();
void webMail();
//void loadCert();
void openWebHelp() ;
void toggleUseOldFormat() ;
void recommendFriends();
void toggleIncludeAllIPs();
void toggleUseShortFormat();
private:
Ui::HomePage *ui;
bool mIncludeAllIPs;
bool mUseShortFormat;
QAction *mIncludeDNSact;
QAction *mIncludeIPHistoryact;
QAction *mIncludeExtIPact;
QAction *mIncludeLocIPact;
QAction *mUseOldFormatact;
RsEventsHandlerId_t mEventHandlerId;

View File

@ -1083,7 +1083,9 @@ void SetForegroundWindowInternal(HWND hWnd)
return _instance->gxsforumDialog;
case Posted:
return _instance->postedDialog;
}
case Home:
return _instance->homePage;
}
return NULL;
}

View File

@ -100,9 +100,10 @@ public:
Channels = 6, /** Channels page. */
Forums = 7, /** Forums page. */
Search = 8, /** Search page. */
Posted = 11, /** Posted links */
People = 12, /** People page. */
Options = 13 /** People page. */
Posted = 11, /** Posted links */
People = 12, /** People page. */
Options = 13, /** People page. */
Home = 14 /** Home page. */
};

View File

@ -22,6 +22,7 @@
#include "ChatLobbyWidget.h"
#include "MainWindow.h"
#include "HomePage.h"
#include "chat/ChatDialog.h"
#include "common/PeerDefs.h"
#include "common/RsCollection.h"
@ -551,32 +552,41 @@ RetroShareLink RetroShareLink::createMessage(const RsGxsId& peerId, const QStrin
RetroShareLink RetroShareLink::createCertificate(const RsPeerId& ssl_id)
{
RetroShareLink link;
link.clear();
RetroShareLink link;
link.clear();
#ifndef RS_NO_WARN_CPP
#pragma message("csoler 2012-08-14: This is baaaaaad code")
#endif
// - we should not need to parse and re-read a cert in old format.
//
RsPeerDetails detail;
if (rsPeers->getPeerDetails(ssl_id, detail) == false) {
std::cerr << "RetroShareLink::createPerson() Couldn't find peer id " << ssl_id << std::endl;
} else {
// - we should not need to parse and re-read a cert in old format.
//
RsPeerDetails detail;
if (rsPeers->getPeerDetails(ssl_id, detail) == false)
std::cerr << "RetroShareLink::createPerson() Couldn't find peer id " << ssl_id << std::endl;
else
{
link._type = TYPE_CERTIFICATE;
link._type = TYPE_CERTIFICATE;
link._radix = QString::fromUtf8(rsPeers->GetRetroshareInvite(ssl_id).c_str());
link._name = QString::fromUtf8(detail.name.c_str());
link._location = QString::fromUtf8(detail.location.c_str());
link._radix.replace("\n","");
if(rsPeers->getOwnId() == ssl_id) // in this case, use application-wide parameters set in HomePage
{
QString invite,description;
static_cast<HomePage*>(MainWindow::getPage(MainWindow::Home))->getOwnCert(invite,description);
link._radix = invite;
}
else
link._radix = QString::fromUtf8(rsPeers->GetRetroshareInvite(ssl_id).c_str());
std::cerr << "Found radix = " << link._radix.toStdString() << std::endl;
}
link._name = QString::fromUtf8(detail.name.c_str());
link._location = QString::fromUtf8(detail.location.c_str());
link._radix.replace("\n","");
link.check();
std::cerr << "Found radix = " << link._radix.toStdString() << std::endl;
}
return link;
link.check();
return link;
}
RetroShareLink RetroShareLink::createUnknownSslCertificate(const RsPeerId& sslId, const RsPgpId& gpgId)
{

View File

@ -1361,7 +1361,7 @@ bool NewFriendList::exportFriendlist(QString &fileName)
if (!rsPeers->getPeerDetails(*list_iter2, detailSSL))
continue;
std::string certificate = rsPeers->GetRetroshareInvite(detailSSL.id, RetroshareInviteFlags::CURRENT_IP | RetroshareInviteFlags::DNS | RetroshareInviteFlags::RADIX_FORMAT);
std::string certificate = rsPeers->GetRetroshareInvite(detailSSL.id, RsPeers::defaultCertificateFlags | RetroshareInviteFlags::RADIX_FORMAT);
// remove \n from certificate
certificate.erase(std::remove(certificate.begin(), certificate.end(), '\n'), certificate.end());

View File

@ -264,7 +264,7 @@ void ConfCertDialog::loadInvitePage()
ui._shouldAddSignatures_CB->setEnabled(detail.gpgSigners.size() > 1) ;
std::string invite ;
RetroshareInviteFlags flags = RetroshareInviteFlags::DNS | RetroshareInviteFlags::CURRENT_IP | RetroshareInviteFlags::RADIX_FORMAT;
RetroshareInviteFlags flags = RsPeers::defaultCertificateFlags | RetroshareInviteFlags::RADIX_FORMAT;
if(!detail.isHiddenNode && ui._includeIPHistory_CB->isChecked())
flags |= RetroshareInviteFlags::FULL_IP_HISTORY;
@ -283,7 +283,7 @@ void ConfCertDialog::loadInvitePage()
ui.stabWidget->setTabText(PageCertificate, tr("Retroshare Certificate"));
}
QString infotext = getCertificateDescription(detail,ui._shouldAddSignatures_CB->isChecked(),ui._shortFormat_CB->isChecked(), ui._includeIPHistory_CB->isChecked() );
QString infotext = getCertificateDescription(detail,ui._shouldAddSignatures_CB->isChecked(),ui._shortFormat_CB->isChecked(), flags );
ui.userCertificateText->setToolTip(infotext) ;
@ -297,19 +297,15 @@ void ConfCertDialog::loadInvitePage()
ui.userCertificateText->setText(QString::fromUtf8(invite.c_str()));
}
QString ConfCertDialog::getCertificateDescription(const RsPeerDetails& detail,bool signatures_included,bool use_short_format,bool include_additional_locators)
QString ConfCertDialog::getCertificateDescription(const RsPeerDetails& detail, bool signatures_included, bool use_short_format,RetroshareInviteFlags invite_flags)
{
//infotext += tr("<p>Use this certificate to make new friends. Send it by email, or give it hand to hand.</p>") ;
QString infotext;
if(use_short_format)
{
infotext += tr("<p>This Retroshare ID contains:") ;
}
else
{
infotext += tr("<p>This certificate contains:") ;
}
infotext += "<UL>" ;
@ -334,25 +330,36 @@ QString ConfCertDialog::getCertificateDescription(const RsPeerDetails& detail,bo
if(detail.isHiddenNode)
infotext += tr("<li> <b>onion address</b> and <b>port</b>") +" (" + detail.hiddenNodeAddress.c_str() + ":" + QString::number(detail.hiddenNodePort)+ ")</li>";
else if(!include_additional_locators)
else if(!!(invite_flags & RetroshareInviteFlags::FULL_IP_HISTORY))
for(auto it(detail.ipAddressList.begin());it!=detail.ipAddressList.end();++it)
{
infotext += "<li>" ;
infotext += tr("<b>IP address</b> and <b>port</b>: ") + QString::fromStdString(*it) ;
infotext += "</li>" ;
}
else
{
if(!detail.localAddr.empty()) infotext += tr("<li><b>IP address</b> and <b>port</b>: ") + detail.localAddr.c_str() + ":" + QString::number(detail.localPort)+ "</li>";
if(!detail.extAddr.empty()) infotext += tr("<li><b>IP address</b> and <b>port</b>: ") + detail.extAddr.c_str() + ":" + QString::number(detail.extPort)+ "</li>";
if(!!(invite_flags & RetroshareInviteFlags::CURRENT_LOCAL_IP) && !detail.localAddr.empty())
infotext += tr("<li><b>IP address</b> and <b>port</b>: ") + detail.localAddr.c_str() + ":" + QString::number(detail.localPort)+ "</li>";
if(!!(invite_flags & RetroshareInviteFlags::CURRENT_EXTERNAL_IP) && !detail.extAddr.empty())
infotext += tr("<li><b>IP address</b> and <b>port</b>: ") + detail.extAddr.c_str() + ":" + QString::number(detail.extPort)+ "</li>";
}
if(!!(invite_flags & RetroshareInviteFlags::DNS) && !detail.dyndns.empty())
{
infotext += "<li>" ;
infotext += tr("<b>DNS:</b> : ") + QString::fromStdString(detail.dyndns);
infotext += "</li>" ;
}
else for(auto it(detail.ipAddressList.begin());it!=detail.ipAddressList.end();++it)
{
infotext += "<li>" ;
infotext += tr("<b>IP address</b> and <b>port</b>: ") + QString::fromStdString(*it) ;
infotext += "</li>" ;
}
infotext += QString("</p>") ;
if(rsPeers->getOwnId() == detail.id)
if(use_short_format)
infotext += tr("<p>You can use this Retroshare ID to make new friends. Send it by email, or give it hand to hand.</p>") ;
else
infotext += tr("<p>You can use this certificate to make new friends. Send it by email, or give it hand to hand.</p>") ;
infotext += tr("<p>You can use this Retroshare ID to make new friends. Send it by email, or give it hand to hand.</p>") ;
else
infotext += tr("<p>You can use this certificate to make new friends. Send it by email, or give it hand to hand.</p>") ;
return infotext;
}

View File

@ -59,7 +59,7 @@ public:
/* window will destroy itself! */
}
static void loadAll();
static QString getCertificateDescription(const RsPeerDetails& det, bool signatures_included, bool use_short_format, bool extra_locators_included);
static QString getCertificateDescription(const RsPeerDetails& det, bool signatures_included, bool use_short_format,RetroshareInviteFlags invite_flags);
signals:
void configChanged();

View File

@ -891,7 +891,9 @@ void ConnectFriendWizard::cleanFriendCert()
whileBlocking(ui->friendCertEdit)->setPlainText(QString::fromUtf8(cleanCert.c_str()));
whileBlocking(ui->friendCertEdit)->setTextCursor(textCursor);
certDetail = ConfCertDialog::getCertificateDescription(details,false,mIsShortInvite,!details.ipAddressList.empty());
// use dummy flags so that the content of the description is driven by what's in the "details" variable.
RetroshareInviteFlags dummy_flags = RetroshareInviteFlags::ALL;
certDetail = ConfCertDialog::getCertificateDescription(details,false,mIsShortInvite,dummy_flags);
}
if (mIsShortInvite)

View File

@ -61,6 +61,10 @@ CryptoPage::CryptoPage(QWidget * parent, Qt::WindowFlags flags)
//connect(ui.exportprofile,SIGNAL(clicked()), this, SLOT(profilemanager()));
connect(ui.exportprofile,SIGNAL(clicked()), this, SLOT(exportProfile()));
// Remove this because it duplicates functionality of the HomePage.
ui.retroshareId_LB->hide();
ui.retroshareId_content_LB->hide();
ui.stackPageCertificate->hide();
ui.onlinesince->setText(DateTime::formatLongDateTime(Rshare::startupTime()));
}
@ -103,8 +107,8 @@ void CryptoPage::showEvent ( QShowEvent * /*event*/ )
ui.pgpfingerprint->setText(misc::fingerPrintStyleSplit(QString::fromStdString(detail.fpr.toStdString())));
std::string invite ;
rsPeers->getShortInvite(invite,rsPeers->getOwnId(),RetroshareInviteFlags::RADIX_FORMAT | RetroshareInviteFlags::DNS | RetroshareInviteFlags::CURRENT_IP);
ui.retroshareid->setText(QString::fromUtf8(invite.c_str()));
rsPeers->getShortInvite(invite,rsPeers->getOwnId(),RetroshareInviteFlags::RADIX_FORMAT | RsPeers::defaultCertificateFlags);
ui.retroshareId_content_LB->setText(QString::fromUtf8(invite.c_str()));
/* set retroshare version */
ui.version->setText(Rshare::retroshareVersion(true));
@ -139,7 +143,7 @@ void
CryptoPage::load()
{
std::string cert ;
RetroshareInviteFlags flags = RetroshareInviteFlags::DNS | RetroshareInviteFlags::CURRENT_IP;
RetroshareInviteFlags flags = RetroshareInviteFlags::DNS | RetroshareInviteFlags::CURRENT_LOCAL_IP | RetroshareInviteFlags::CURRENT_EXTERNAL_IP;
if(ui._shortFormat_CB->isChecked())
{
@ -161,7 +165,7 @@ CryptoPage::load()
RsPeerDetails detail;
rsPeers->getPeerDetails(rsPeers->getOwnId(),detail);
ui.certplainTextEdit->setToolTip(ConfCertDialog::getCertificateDescription(detail, ui._includeSignatures_CB->isChecked(), ui._shortFormat_CB->isChecked(), ui._includeAllIPs_CB->isChecked() ));
ui.certplainTextEdit->setToolTip(ConfCertDialog::getCertificateDescription(detail, ui._includeSignatures_CB->isChecked(), ui._shortFormat_CB->isChecked(), flags));
}
void

View File

@ -7,25 +7,19 @@
<x>0</x>
<y>0</y>
<width>869</width>
<height>487</height>
<height>493</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Node information</string>
</attribute>
<widget class="QStackedWidget" name="stackedWidget">
<widget class="QWidget" name="stackPageNodeInfo" native="true">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox_1">
<layout class="QGridLayout" name="gridLayout_4">
<item row="6" column="0">
<widget class="QLabel" name="label">
<widget class="QLabel" name="retroshareId_LB">
<property name="text">
<string>Retroshare ID:</string>
</property>
@ -248,7 +242,7 @@
<item row="14" column="1">
<widget class="QPushButton" name="exportprofile">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use this to export your profile key. You can then import it in a different computer and make a new node with the same profile. Doing so, existing friends that you also add to the new node will automatically recognise that new node as friend.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use this button to export your profile key. You can then import it in a different computer and make a new node with the same profile. Doing so, existing friends that you also add to the new node will automatically recognise that new node as friend.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Export</string>
@ -474,7 +468,7 @@
</widget>
</item>
<item row="6" column="1" colspan="3">
<widget class="QLabel" name="retroshareid">
<widget class="QLabel" name="retroshareId_content_LB">
<property name="font">
<font>
<weight>75</weight>
@ -539,10 +533,7 @@
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Certificate</string>
</attribute>
<widget class="QWidget" name="stackPageCertificate" native="true">
<layout class="QGridLayout" name="gridLayout_7">
<item row="0" column="0">
<widget class="QPlainTextEdit" name="certplainTextEdit">