mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-10-01 02:35:48 -04:00
Merge pull request #2073 from csoler/v0.6-TorV3
Compatibility with Tor v3, with retrocompatibility for existing nodes
This commit is contained in:
commit
2d17874d2d
@ -1392,7 +1392,7 @@ bool p3Peers::parseShortInvite(const std::string& inviteStrUrl, RsPeerDetails& d
|
||||
case RsShortInviteFieldType::HIDDEN_LOCATOR:
|
||||
details.hiddenType = (((uint32_t)buf[0]) << 24)+(((uint32_t)buf[1])<<16)+(((uint32_t)buf[2])<<8) + (uint32_t)buf[3];
|
||||
details.hiddenNodePort = (((uint32_t)buf[4]) << 8)+ (uint32_t)buf[5];
|
||||
|
||||
details.isHiddenNode = true;
|
||||
details.hiddenNodeAddress = std::string((char*)&buf[6],s-6);
|
||||
break;
|
||||
|
||||
@ -1538,7 +1538,7 @@ std::string p3Peers::GetRetroshareInvite(
|
||||
|
||||
if (getPeerDetails(ssl_id, detail))
|
||||
{
|
||||
if(!includeExtraLocators) detail.ipAddressList.clear();
|
||||
if(!includeExtraLocators && !detail.isHiddenNode) detail.ipAddressList.clear();
|
||||
|
||||
unsigned char *mem_block = nullptr;
|
||||
size_t mem_block_size = 0;
|
||||
|
@ -53,10 +53,12 @@ QByteArray AddOnionCommand::build()
|
||||
QByteArray out("ADD_ONION");
|
||||
|
||||
if (m_service->privateKey().isLoaded()) {
|
||||
out += " RSA1024:";
|
||||
out += m_service->privateKey().encodedPrivateKey(CryptoKey::DER).toBase64();
|
||||
out += " ";
|
||||
out += m_service->privateKey().bytes();
|
||||
} else {
|
||||
out += " NEW:RSA1024";
|
||||
//out += " NEW:RSA1024"; // this is v2. For v3, use NEW:BEST, or NEW:ED25519-V3
|
||||
//out += " NEW:ED25519-V3"; // this is v3.
|
||||
out += " NEW:BEST"; // this is v3, but without control of key type. Generates a RSA1024 key on older Tor versions.
|
||||
}
|
||||
|
||||
foreach (const HiddenService::Target &target, m_service->targets()) {
|
||||
@ -80,12 +82,21 @@ void AddOnionCommand::onReply(int statusCode, const QByteArray &data)
|
||||
return;
|
||||
}
|
||||
|
||||
const QByteArray keyPrefix("PrivateKey=RSA1024:");
|
||||
const QByteArray keyPrefix("PrivateKey=");
|
||||
const QByteArray sidPrefix("ServiceID=");
|
||||
|
||||
if(data.startsWith("ServiceID=")){
|
||||
QByteArray service_id = data.mid(sidPrefix.size());
|
||||
m_service->setServiceId(service_id);
|
||||
}
|
||||
|
||||
if (data.startsWith(keyPrefix)) {
|
||||
QByteArray keyData(QByteArray::fromBase64(data.mid(keyPrefix.size())));
|
||||
|
||||
QByteArray keyData(data.mid(keyPrefix.size()));
|
||||
CryptoKey key;
|
||||
if (!key.loadFromData(keyData, CryptoKey::PrivateKey, CryptoKey::DER)) {
|
||||
m_errorMessage = QStringLiteral("Key decoding failed");
|
||||
|
||||
if (!key.loadFromTorMessage(keyData)) {
|
||||
m_errorMessage = QStringLiteral("Key structure check failed");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -30,11 +30,14 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "CryptoKey.h"
|
||||
#include "SecureRNG.h"
|
||||
#include "Useful.h"
|
||||
#include <QtDebug>
|
||||
#include <QFile>
|
||||
#include <QByteArray>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/pem.h>
|
||||
@ -48,8 +51,10 @@ void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
|
||||
#define RSA_bits(o) (BN_num_bits((o)->n))
|
||||
#endif
|
||||
|
||||
#ifdef TO_REMOVE
|
||||
void base32_encode(char *dest, unsigned destlen, const char *src, unsigned srclen);
|
||||
bool base32_decode(char *dest, unsigned destlen, const char *src, unsigned srclen);
|
||||
#endif
|
||||
|
||||
CryptoKey::CryptoKey()
|
||||
{
|
||||
@ -60,6 +65,7 @@ CryptoKey::~CryptoKey()
|
||||
clear();
|
||||
}
|
||||
|
||||
#ifdef TO_REMOVE
|
||||
CryptoKey::Data::~Data()
|
||||
{
|
||||
if (key)
|
||||
@ -68,12 +74,14 @@ CryptoKey::Data::~Data()
|
||||
key = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void CryptoKey::clear()
|
||||
{
|
||||
d = 0;
|
||||
key_data.clear();
|
||||
}
|
||||
|
||||
#ifdef TO_REMOVE
|
||||
bool CryptoKey::loadFromData(const QByteArray &data, KeyType type, KeyFormat format)
|
||||
{
|
||||
RSA *key = NULL;
|
||||
@ -110,23 +118,91 @@ bool CryptoKey::loadFromData(const QByteArray &data, KeyType type, KeyFormat for
|
||||
d = new Data(key);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool CryptoKey::loadFromFile(const QString &path, KeyType type, KeyFormat format)
|
||||
bool CryptoKey::loadFromFile(const QString& path)
|
||||
{
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
qWarning() << "Failed to open" << (type == PrivateKey ? "private" : "public") << "key from"
|
||||
<< path << "-" << file.errorString();
|
||||
qWarning() << "Failed to open Tor key file " << path << ": " << file.errorString();
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray data = file.readAll();
|
||||
file.close();
|
||||
|
||||
return loadFromData(data, type, format);
|
||||
if(data.contains("-----BEGIN RSA PRIVATE KEY-----"))
|
||||
{
|
||||
std::cerr << "Note: Reading/converting Tor v2 key format." << std::endl;
|
||||
|
||||
// This to be compliant with old format. New format is oblivious to the type of key so we dont need a header
|
||||
data = data.replace("-----BEGIN RSA PRIVATE KEY-----",nullptr);
|
||||
data = data.replace("-----END RSA PRIVATE KEY-----",nullptr);
|
||||
data = data.replace("\n",nullptr);
|
||||
data = data.replace("\t",nullptr);
|
||||
|
||||
data = "RSA1024:"+data;
|
||||
}
|
||||
|
||||
std::cerr << "Have read the following key: " << std::endl;
|
||||
std::cerr << QString(data).toStdString() << std::endl;
|
||||
|
||||
key_data = data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptoKey::loadFromTorMessage(const QByteArray& b)
|
||||
{
|
||||
// note: We should probably check the structure a bit more, for security.
|
||||
|
||||
std::cerr << "Loading new key:" << std::endl;
|
||||
|
||||
if(b.startsWith("RSA1024"))
|
||||
std::cerr << " type: RSA-1024 (Tor v2)" << std::endl;
|
||||
else if(b.startsWith("ED25519-V3"))
|
||||
std::cerr << " type: ED25519-V3 (Tor v3)" << std::endl;
|
||||
else if(b.indexOf(':'))
|
||||
{
|
||||
std::cerr << " unknown type, or bad syntax in key: \"" << b.left(b.indexOf(':')).toStdString() << "\". Not accepted." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
key_data = b;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Cryptographic hash of a password as expected by Tor's HashedControlPassword */
|
||||
QByteArray torControlHashedPassword(const QByteArray &password)
|
||||
{
|
||||
QByteArray salt = SecureRNG::random(8);
|
||||
if (salt.isNull())
|
||||
return QByteArray();
|
||||
|
||||
int count = ((quint32)16 + (96 & 15)) << ((96 >> 4) + 6);
|
||||
|
||||
SHA_CTX hash;
|
||||
SHA1_Init(&hash);
|
||||
|
||||
QByteArray tmp = salt + password;
|
||||
while (count)
|
||||
{
|
||||
int c = qMin(count, tmp.size());
|
||||
SHA1_Update(&hash, reinterpret_cast<const void*>(tmp.constData()), c);
|
||||
count -= c;
|
||||
}
|
||||
|
||||
unsigned char md[20];
|
||||
SHA1_Final(md, &hash);
|
||||
|
||||
/* 60 is the hex-encoded value of 96, which is a constant used by Tor's algorithm. */
|
||||
return QByteArray("16:") + salt.toHex().toUpper() + QByteArray("60") +
|
||||
QByteArray::fromRawData(reinterpret_cast<const char*>(md), 20).toHex().toUpper();
|
||||
}
|
||||
|
||||
|
||||
#ifdef TO_REMOVE
|
||||
bool CryptoKey::isPrivate() const
|
||||
{
|
||||
if (!isLoaded()) {
|
||||
@ -326,34 +402,6 @@ bool CryptoKey::verifySHA256(const QByteArray &digest, QByteArray signature) con
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Cryptographic hash of a password as expected by Tor's HashedControlPassword */
|
||||
QByteArray torControlHashedPassword(const QByteArray &password)
|
||||
{
|
||||
QByteArray salt = SecureRNG::random(8);
|
||||
if (salt.isNull())
|
||||
return QByteArray();
|
||||
|
||||
int count = ((quint32)16 + (96 & 15)) << ((96 >> 4) + 6);
|
||||
|
||||
SHA_CTX hash;
|
||||
SHA1_Init(&hash);
|
||||
|
||||
QByteArray tmp = salt + password;
|
||||
while (count)
|
||||
{
|
||||
int c = qMin(count, tmp.size());
|
||||
SHA1_Update(&hash, reinterpret_cast<const void*>(tmp.constData()), c);
|
||||
count -= c;
|
||||
}
|
||||
|
||||
unsigned char md[20];
|
||||
SHA1_Final(md, &hash);
|
||||
|
||||
/* 60 is the hex-encoded value of 96, which is a constant used by Tor's algorithm. */
|
||||
return QByteArray("16:") + salt.toHex().toUpper() + QByteArray("60") +
|
||||
QByteArray::fromRawData(reinterpret_cast<const char*>(md), 20).toHex().toUpper();
|
||||
}
|
||||
|
||||
/* Copyright (c) 2001-2004, Roger Dingledine
|
||||
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson
|
||||
* Copyright (c) 2007-2010, The Tor Project, Inc.
|
||||
@ -475,3 +523,5 @@ bool base32_decode(char *dest, unsigned destlen, const char *src, unsigned srcle
|
||||
delete[] tmp;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -51,14 +51,19 @@ public:
|
||||
};
|
||||
|
||||
CryptoKey();
|
||||
CryptoKey(const CryptoKey &other) : d(other.d) { }
|
||||
~CryptoKey();
|
||||
|
||||
#ifdef TO_REMOVE
|
||||
bool loadFromData(const QByteArray &data, KeyType type, KeyFormat format = PEM);
|
||||
bool loadFromFile(const QString &path, KeyType type, KeyFormat format = PEM);
|
||||
#endif
|
||||
bool loadFromFile(const QString &path);
|
||||
void clear();
|
||||
|
||||
bool isLoaded() const { return d.data() && d->key != 0; }
|
||||
const QByteArray bytes() const { return key_data; }
|
||||
bool loadFromTorMessage(const QByteArray& b);
|
||||
bool isLoaded() const { return !key_data.isNull(); }
|
||||
#ifdef TO_REMOVE
|
||||
bool isPrivate() const;
|
||||
|
||||
QByteArray publicKeyDigest() const;
|
||||
@ -76,8 +81,10 @@ public:
|
||||
QByteArray signSHA256(const QByteArray &digest) const;
|
||||
// Verify a signature as per signSHA256
|
||||
bool verifySHA256(const QByteArray &digest, QByteArray signature) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
#ifdef TO_REMOVE
|
||||
struct Data : public QSharedData
|
||||
{
|
||||
typedef struct rsa_st RSA;
|
||||
@ -86,8 +93,12 @@ private:
|
||||
Data(RSA *k = 0) : key(k) { }
|
||||
~Data();
|
||||
};
|
||||
#endif
|
||||
|
||||
QByteArray key_data;
|
||||
#ifdef TO_REMOVE
|
||||
QExplicitlySharedDataPointer<Data> d;
|
||||
#endif
|
||||
};
|
||||
|
||||
QByteArray torControlHashedPassword(const QByteArray &password);
|
||||
|
@ -90,6 +90,13 @@ void HiddenService::addTarget(quint16 servicePort, QHostAddress targetAddress, q
|
||||
m_targets.append(t);
|
||||
}
|
||||
|
||||
void HiddenService::setServiceId(const QByteArray& sid)
|
||||
{
|
||||
m_service_id = sid;
|
||||
m_hostname = sid + ".onion";
|
||||
|
||||
emit hostnameChanged();
|
||||
}
|
||||
void HiddenService::setPrivateKey(const CryptoKey &key)
|
||||
{
|
||||
if (m_privateKey.isLoaded()) {
|
||||
@ -97,13 +104,15 @@ void HiddenService::setPrivateKey(const CryptoKey &key)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TO_REMOVE
|
||||
if (!key.isPrivate()) {
|
||||
BUG() << "Cannot create a hidden service with a public key";
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_privateKey = key;
|
||||
m_hostname = m_privateKey.torServiceID() + QStringLiteral(".onion");
|
||||
|
||||
emit privateKeyChanged();
|
||||
}
|
||||
|
||||
@ -112,13 +121,13 @@ void HiddenService::loadPrivateKey()
|
||||
if (m_privateKey.isLoaded() || m_dataPath.isEmpty())
|
||||
return;
|
||||
|
||||
bool ok = m_privateKey.loadFromFile(m_dataPath + QLatin1String("/private_key"), CryptoKey::PrivateKey);
|
||||
bool ok = m_privateKey.loadFromFile(m_dataPath + QLatin1String("/private_key"));
|
||||
|
||||
if (!ok) {
|
||||
qWarning() << "Failed to load hidden service key";
|
||||
return;
|
||||
}
|
||||
|
||||
m_hostname = m_privateKey.torServiceID();
|
||||
emit privateKeyChanged();
|
||||
}
|
||||
|
||||
|
@ -70,11 +70,13 @@ public:
|
||||
|
||||
Status status() const { return m_status; }
|
||||
|
||||
const QString &hostname() const { return m_hostname; }
|
||||
const QString &dataPath() const { return m_dataPath; }
|
||||
const QString& hostname() const { return m_hostname; }
|
||||
const QString serviceId() const { return QString(m_service_id); }
|
||||
const QString& dataPath() const { return m_dataPath; }
|
||||
|
||||
CryptoKey privateKey() { return m_privateKey; }
|
||||
void setPrivateKey(const CryptoKey &privateKey);
|
||||
void setServiceId(const QByteArray& sid);
|
||||
|
||||
const QList<Target> &targets() const { return m_targets; }
|
||||
void addTarget(const Target &target);
|
||||
@ -84,6 +86,7 @@ signals:
|
||||
void statusChanged(int newStatus, int oldStatus);
|
||||
void serviceOnline();
|
||||
void privateKeyChanged();
|
||||
void hostnameChanged();
|
||||
|
||||
private slots:
|
||||
void servicePublished();
|
||||
@ -94,6 +97,7 @@ private:
|
||||
QString m_hostname;
|
||||
Status m_status;
|
||||
CryptoKey m_privateKey;
|
||||
QByteArray m_service_id;
|
||||
|
||||
void loadPrivateKey();
|
||||
void setStatus(Status newStatus);
|
||||
|
@ -174,17 +174,16 @@ bool TorManager::setupHiddenService()
|
||||
std::cerr << "Attempting to load key from legacy filesystem format in " << legacyDir.toStdString() << std::endl;
|
||||
|
||||
CryptoKey key;
|
||||
if (!key.loadFromFile(legacyDir + QLatin1String("/private_key"), CryptoKey::PrivateKey))
|
||||
if (!key.loadFromFile(legacyDir + QLatin1String("/private_key")))
|
||||
{
|
||||
qWarning() << "Cannot load legacy format key from" << legacyDir << "for conversion";
|
||||
return false;
|
||||
}
|
||||
|
||||
keyData = QString::fromLatin1(key.encodedPrivateKey(CryptoKey::DER).toBase64());
|
||||
d->hiddenService = new Tor::HiddenService(key, legacyDir, this);
|
||||
|
||||
std::cerr << "Got key from legacy dir: " << std::endl;
|
||||
std::cerr << keyData.toStdString() << std::endl;
|
||||
std::cerr << key.bytes().toStdString() << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -193,6 +192,7 @@ bool TorManager::setupHiddenService()
|
||||
std::cerr << "Creating new hidden service." << std::endl;
|
||||
|
||||
connect(d->hiddenService, SIGNAL(privateKeyChanged()), this, SLOT(hiddenServicePrivateKeyChanged())) ;
|
||||
connect(d->hiddenService, SIGNAL(hostnameChanged()), this, SLOT(hiddenServiceHostnameChanged())) ;
|
||||
}
|
||||
|
||||
Q_ASSERT(d->hiddenService);
|
||||
@ -230,31 +230,40 @@ void TorManager::hiddenServiceStatusChanged(int old_status,int new_status)
|
||||
|
||||
void TorManager::hiddenServicePrivateKeyChanged()
|
||||
{
|
||||
QString key = QString::fromLatin1(d->hiddenService->privateKey().encodedPrivateKey(CryptoKey::DER).toBase64());
|
||||
QString key = QString::fromLatin1(d->hiddenService->privateKey().bytes());
|
||||
|
||||
QFile outfile(d->hiddenServiceDir + QLatin1String("/private_key")) ;
|
||||
outfile.open( QIODevice::WriteOnly | QIODevice::Text );
|
||||
QTextStream s(&outfile);
|
||||
|
||||
#ifdef TO_REMOVE
|
||||
s << "-----BEGIN RSA PRIVATE KEY-----" << endl;
|
||||
|
||||
for(uint32_t i=0;i<key.length();i+=64)
|
||||
for(int i=0;i<key.length();i+=64)
|
||||
s << key.mid(i,64) << endl ;
|
||||
|
||||
s << "-----END RSA PRIVATE KEY-----" << endl;
|
||||
#endif
|
||||
s << key ;
|
||||
|
||||
outfile.close();
|
||||
|
||||
std::cerr << "Hidden service private key changed!" << std::endl;
|
||||
std::cerr << key.toStdString() << std::endl;
|
||||
}
|
||||
|
||||
QFile outfile2(d->hiddenServiceDir + QLatin1String("/hostname")) ;
|
||||
void TorManager::hiddenServiceHostnameChanged()
|
||||
{
|
||||
QFile outfile2(d->hiddenServiceDir + QLatin1String("/hostname")) ;
|
||||
outfile2.open( QIODevice::WriteOnly | QIODevice::Text );
|
||||
QTextStream t(&outfile2);
|
||||
|
||||
t << d->hiddenService->hostname() << endl;
|
||||
QString hostname(d->hiddenService->hostname());
|
||||
|
||||
outfile2.close();
|
||||
t << hostname << endl;
|
||||
outfile2.close();
|
||||
|
||||
std::cerr << "Hidden service hostname changed: " << hostname.toStdString() << std::endl;
|
||||
}
|
||||
|
||||
bool TorManager::configurationNeeded() const
|
||||
@ -381,7 +390,7 @@ bool TorManager::getHiddenServiceInfo(QString& service_id,QString& service_onion
|
||||
for(auto it(hidden_services.begin());it!=hidden_services.end();++it)
|
||||
{
|
||||
service_onion_address = (*it)->hostname();
|
||||
service_id = (*it)->privateKey().torServiceID();
|
||||
service_id = (*it)->serviceId();
|
||||
|
||||
for(auto it2((*it)->targets().begin());it2!=(*it)->targets().end();++it2)
|
||||
{
|
||||
|
@ -93,7 +93,8 @@ public slots:
|
||||
|
||||
private slots:
|
||||
void hiddenServicePrivateKeyChanged();
|
||||
void hiddenServiceStatusChanged(int old_status,int new_status);
|
||||
void hiddenServiceHostnameChanged();
|
||||
void hiddenServiceStatusChanged(int old_status,int new_status);
|
||||
|
||||
signals:
|
||||
void configurationNeededChanged();
|
||||
|
@ -189,8 +189,6 @@ void HomePage::updateOwnCert()
|
||||
|
||||
void HomePage::updateOwnId()
|
||||
{
|
||||
bool include_extra_locators = mIncludeAllIPs;
|
||||
|
||||
RsPeerDetails detail;
|
||||
|
||||
if (!rsPeers->getPeerDetails(rsPeers->getOwnId(), detail))
|
||||
@ -199,11 +197,30 @@ void HomePage::updateOwnId()
|
||||
return ;
|
||||
}
|
||||
|
||||
std::string invite ;
|
||||
bool include_extra_locators = mIncludeAllIPs || detail.isHiddenNode;
|
||||
std::string invite ;
|
||||
|
||||
rsPeers->getShortInvite(invite,rsPeers->getOwnId(),true,!mIncludeAllIPs);
|
||||
rsPeers->getShortInvite(invite,rsPeers->getOwnId(),true,!include_extra_locators);
|
||||
|
||||
ui->retroshareid->setText(QString::fromUtf8(invite.c_str()));
|
||||
#ifdef TODO
|
||||
QString S;
|
||||
QString txt;
|
||||
int i=0;
|
||||
|
||||
for(uint32_t i=0;i<invite.size();)
|
||||
if(QFontMetricsF(font()).width(S) < ui->retroshareid->width())
|
||||
S += invite[i++];
|
||||
else
|
||||
{
|
||||
txt += S + "\n";
|
||||
S.clear();
|
||||
}
|
||||
|
||||
txt += S;
|
||||
|
||||
ui->retroshareid->setText(txt);
|
||||
#endif
|
||||
ui->retroshareid->setText(QString::fromUtf8(invite.c_str()));
|
||||
}
|
||||
static void sendMail(QString sAddress, QString sSubject, QString sBody)
|
||||
{
|
||||
|
@ -174,7 +174,7 @@ private and secure decentralized communication platform.
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="images.qrc">
|
||||
<iconset resource="icons.qrc">
|
||||
<normaloff>:/icons/help_64.png</normaloff>:/icons/help_64.png</iconset>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
@ -186,22 +186,16 @@ private and secure decentralized communication platform.
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="QToolButton" name="shareButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<widget class="QToolButton" name="expandButton">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Share your RetroShare ID</p></body></html></string>
|
||||
<string>Show full certificate (old format)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="icons.qrc">
|
||||
<normaloff>:/icons/svg/share.svg</normaloff>:/icons/svg/share.svg</iconset>
|
||||
<normaloff>:/icons/png/cert.png</normaloff>:/icons/png/cert.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
@ -209,8 +203,8 @@ private and secure decentralized communication platform.
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="popupMode">
|
||||
<enum>QToolButton::InstantPopup</enum>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
@ -218,7 +212,7 @@ private and secure decentralized communication platform.
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="retroshareid">
|
||||
<widget class="ElidedLabel" name="retroshareid">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
@ -232,12 +226,36 @@ private and secure decentralized communication platform.
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="5">
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="userCertLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>11</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>This is your Retroshare ID. Copy and share with your friends!</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="6">
|
||||
<widget class="QPlainTextEdit" name="userCertEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
@ -273,38 +291,23 @@ private and secure decentralized communication platform.
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="userCertLabel">
|
||||
<item row="1" column="3">
|
||||
<widget class="QToolButton" name="shareButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>11</pointsize>
|
||||
</font>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>This is your Retroshare ID. Copy and share with your friends!</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QToolButton" name="expandButton">
|
||||
<property name="toolTip">
|
||||
<string>Show full certificate (old format)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
<string><html><head/><body><p>Share your RetroShare ID</p></body></html></string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="icons.qrc">
|
||||
<normaloff>:/icons/png/cert.png</normaloff>:/icons/png/cert.png</iconset>
|
||||
<normaloff>:/icons/svg/share.svg</normaloff>:/icons/svg/share.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
@ -312,8 +315,8 @@ private and secure decentralized communication platform.
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
<property name="popupMode">
|
||||
<enum>QToolButton::InstantPopup</enum>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
@ -337,9 +340,17 @@ private and secure decentralized communication platform.
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>ElidedLabel</class>
|
||||
<extends>QLabel</extends>
|
||||
<header location="global">gui/common/ElidedLabel.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="images.qrc"/>
|
||||
<include location="icons.qrc"/>
|
||||
<include location="images.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
@ -278,7 +278,7 @@ void ConfCertDialog::loadInvitePage()
|
||||
|
||||
if(ui._shortFormat_CB->isChecked())
|
||||
{
|
||||
rsPeers->getShortInvite(invite,detail.id,true,!ui._includeIPHistory_CB->isChecked() );
|
||||
rsPeers->getShortInvite(invite,detail.id,true,!(ui._includeIPHistory_CB->isChecked()|| detail.isHiddenNode) );
|
||||
ui.stabWidget->setTabText(1, tr("Retroshare ID"));
|
||||
}
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user