Merge branch 'master' of github.com:highfidelity/hifi into entity-joints

This commit is contained in:
Dante Ruiz 2017-12-22 13:23:23 -08:00
commit 7c4f5bd16c
11 changed files with 71 additions and 26 deletions

27
BUILD_LINUX_CHEATSHEET.md Normal file
View file

@ -0,0 +1,27 @@
# this guide is specific to Ubuntu 16.04.
# deb packages of High Fidelity domain server and assignment client are stored on debian.highfidelity.com
sudo su -
apt-get -y update
apt-get install -y software-properties-common
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 15FF1AAE
add-apt-repository "deb http://debian.highfidelity.com stable main"
apt-get -y update
apt-get install -y hifi-domain-server
apt-get install -y hifi-assignment-client
# When installing master/dev builds, the packages are slightly different and you just need to change the last 2 steps to:
apt-get install -y hifi-dev-domain-server
apt-get install -y hifi-dev-assignment-client
# domain server and assignment clients should already be running. The processes are controlled via:
systemctl start hifi-domain-server
systemctl stop hifi-domain-server
# Once the machine is setup and processes are running you should ensure that your firewall exposes port 40100 on TCP and all UDP ports. This will get your domain up and running and you could connect to it (for now) by using High Fidelity Interface and typing in the IP for the place name. (further customizations can be done via http://IPAddress:40100).
# The server always depends on both hifi-domain-server and hifi-assignment-client running at the same time.
# As an additional step, you should ensure that your packages are automatically updated when a new version goes out. You could, for example, set the automatic update checks to happen every hour (though this could potentially result in the domain being unreachable for a whole hour by new clients when they are released - adjust the update checks accordingly).
To do this you can modify /etc/crontab by adding the following lines
0 */1 * * * root apt-get update
1 */1 * * * root apt-get install --only-upgrade -y hifi-domain-server
2 */1 * * * root apt-get install --only-upgrade -y hifi-assignment-client

View file

@ -410,7 +410,8 @@ Rectangle {
Rectangle {
id: buyTextContainer;
visible: buyText.text !== "";
anchors.top: parent.top;
anchors.top: cancelPurchaseButton.bottom;
anchors.topMargin: 16;
anchors.left: parent.left;
anchors.right: parent.right;
height: buyText.height + 30;
@ -465,8 +466,8 @@ Rectangle {
enabled: (root.balanceAfterPurchase >= 0 && purchasesReceived && balanceReceived) || !itemIsJson;
color: hifi.buttons.blue;
colorScheme: hifi.colorSchemes.light;
anchors.top: buyTextContainer.visible ? buyTextContainer.bottom : checkoutActionButtonsContainer.top;
anchors.topMargin: buyTextContainer.visible ? 12 : 16;
anchors.top: checkoutActionButtonsContainer.top;
anchors.topMargin: 16;
height: 40;
anchors.left: parent.left;
anchors.right: parent.right;
@ -926,11 +927,11 @@ Rectangle {
buyText.text = "";
}
} else {
buyText.text = "This free item <b>will not</b> be added to your <b>Purchases</b>. Non-entities can't yet be purchased for HFC.";
buyTextContainer.color = "#FFD6AD";
buyTextContainer.border.color = "#FAC07D";
buyGlyph.text = hifi.glyphs.alert;
buyGlyph.size = 46;
buyText.text = '<i>This type of item cannot currently be certified, so it will not show up in "My Purchases". You can access it again for free from the Marketplace.</i>';
buyTextContainer.color = hifi.colors.white;
buyTextContainer.border.color = hifi.colors.white;
buyGlyph.text = "";
buyGlyph.size = 0;
}
}

View file

@ -61,7 +61,7 @@ void Ledger::send(const QString& endpoint, const QString& success, const QString
void Ledger::signedSend(const QString& propertyName, const QByteArray& text, const QString& key, const QString& endpoint, const QString& success, const QString& fail, const bool controlled_failure) {
auto wallet = DependencyManager::get<Wallet>();
QString signature = key.isEmpty() ? "" : wallet->signWithKey(text, key);
QString signature = wallet->signWithKey(text, key);
QJsonObject request;
request[propertyName] = QString(text);
if (!controlled_failure) {

View file

@ -548,13 +548,16 @@ QStringList Wallet::listPublicKeys() {
// the horror of code pages and so on (changing the bytes) by just returning a base64
// encoded string representing the signature (suitable for http, etc...)
QString Wallet::signWithKey(const QByteArray& text, const QString& key) {
qCInfo(commerce) << "Signing text" << text << "with key" << key;
EC_KEY* ecPrivateKey = NULL;
auto keyFilePathString = keyFilePath().toStdString();
if ((ecPrivateKey = readPrivateKey(keyFilePath().toStdString().c_str()))) {
unsigned char* sig = new unsigned char[ECDSA_size(ecPrivateKey)];
unsigned int signatureBytes = 0;
qCInfo(commerce) << "Hashing and signing plaintext" << text << "with key at address" << ecPrivateKey;
QByteArray hashedPlaintext = QCryptographicHash::hash(text, QCryptographicHash::Sha256);
@ -747,12 +750,10 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer<ReceivedMessage> pack
}
EC_KEY_free(ec);
QByteArray ba = sig.toLocal8Bit();
const char *sigChar = ba.data();
QByteArray textByteArray;
if (status > -1) {
textByteArray = QByteArray(sigChar, (int) strlen(sigChar));
textByteArray = sig.toUtf8();
}
textByteArraySize = textByteArray.size();
int certIDSize = certID.size();

View file

@ -2530,7 +2530,8 @@ bool EntityItemProperties::verifySignature(const QString& publicKey, const QByte
return false;
}
const unsigned char* key = reinterpret_cast<const unsigned char*>(publicKey.toUtf8().constData());
auto keyByteArray = publicKey.toUtf8();
auto key = keyByteArray.constData();
int keyLength = publicKey.length();
BIO *bio = BIO_new_mem_buf((void*)key, keyLength);
@ -2548,19 +2549,23 @@ bool EntityItemProperties::verifySignature(const QString& publicKey, const QByte
// ECSDA verification prototype: note that type is currently ignored
// int ECDSA_verify(int type, const unsigned char *dgst, int dgstlen,
// const unsigned char *sig, int siglen, EC_KEY *eckey);
bool answer = ECDSA_verify(0,
int answer = ECDSA_verify(0,
digest,
digestLength,
signature,
signatureLength,
ec);
long error = ERR_get_error();
if (error != 0) {
const char* error_str = ERR_error_string(error, NULL);
qCWarning(entities) << "ERROR while verifying signature! EC error:" << error_str
if (error != 0 || answer == -1) {
qCWarning(entities) << "ERROR while verifying signature!"
<< "\nKey:" << publicKey << "\nutf8 Key Length:" << keyLength
<< "\nDigest:" << digest << "\nDigest Length:" << digestLength
<< "\nSignature:" << signature << "\nSignature Length:" << signatureLength;
while (error != 0) {
const char* error_str = ERR_error_string(error, NULL);
qCWarning(entities) << "EC error:" << error_str;
error = ERR_get_error();
}
}
EC_KEY_free(ec);
if (bio) {
@ -2569,7 +2574,7 @@ bool EntityItemProperties::verifySignature(const QString& publicKey, const QByte
if (evp_key) {
EVP_PKEY_free(evp_key);
}
return answer;
return (answer == 1);
} else {
if (bio) {
BIO_free(bio);

View file

@ -1189,13 +1189,15 @@ bool EntityTree::verifyNonce(const QString& certID, const QString& nonce, Entity
key = sent.second;
}
QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----";
bool verificationSuccess = EntityItemProperties::verifySignature(annotatedKey.toUtf8(), actualNonce.toUtf8(), nonce.toUtf8());
QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----\n";
QByteArray hashedActualNonce = QCryptographicHash::hash(QByteArray(actualNonce.toUtf8()), QCryptographicHash::Sha256);
bool verificationSuccess = EntityItemProperties::verifySignature(annotatedKey.toUtf8(), hashedActualNonce, QByteArray::fromBase64(nonce.toUtf8()));
if (verificationSuccess) {
qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "succeeded.";
} else {
qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed for nonce" << actualNonce << "key" << key << "signature" << nonce;
qCDebug(entities) << "Ownership challenge for Cert ID" << certID << "failed. Actual nonce:" << actualNonce <<
"\nHashed actual nonce (digest):" << hashedActualNonce << "\nSent nonce (signature)" << nonce << "\nKey" << key;
}
return verificationSuccess;

View file

@ -24,8 +24,7 @@ SentPacketHistory::SentPacketHistory(int size)
}
void SentPacketHistory::packetSent(uint16_t sequenceNumber, const NLPacket& packet) {
void SentPacketHistory::untrackedPacketSent(uint16_t sequenceNumber) {
// check if given seq number has the expected value. if not, something's wrong with
// the code calling this function
uint16_t expectedSequenceNumber = _newestSequenceNumber + (uint16_t)1;
@ -34,6 +33,10 @@ void SentPacketHistory::packetSent(uint16_t sequenceNumber, const NLPacket& pack
<< "Expected:" << expectedSequenceNumber << "Actual:" << sequenceNumber;
}
_newestSequenceNumber = sequenceNumber;
}
void SentPacketHistory::packetSent(uint16_t sequenceNumber, const NLPacket& packet) {
untrackedPacketSent(sequenceNumber);
QWriteLocker locker(&_packetsLock);
_sentPackets.insert(NLPacket::createCopy(packet));

View file

@ -27,6 +27,8 @@ class SentPacketHistory {
public:
SentPacketHistory(int size = MAX_REASONABLE_SEQUENCE_GAP);
void untrackedPacketSent(uint16_t sequenceNumber);
void packetSent(uint16_t sequenceNumber, const NLPacket& packet);
const NLPacket* getPacket(uint16_t sequenceNumber) const;

View file

@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::EntityEdit:
case PacketType::EntityData:
case PacketType::EntityPhysics:
return static_cast<PacketVersion>(EntityVersion::StaticCertJsonVersionOne);
return static_cast<PacketVersion>(EntityVersion::OwnershipChallengeFix);
case PacketType::EntityQuery:
return static_cast<PacketVersion>(EntityQueryPacketVersion::ConnectionIdentifier);

View file

@ -200,7 +200,8 @@ enum class EntityVersion : PacketVersion {
StrokeColorProperty = 77,
HasDynamicOwnershipTests,
HazeEffect,
StaticCertJsonVersionOne
StaticCertJsonVersionOne,
OwnershipChallengeFix,
};
enum class EntityScriptCallMethodVersion : PacketVersion {

View file

@ -291,6 +291,9 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, QByteArray&
// release the new packet
releaseQueuedPacketList(nodeUUID, std::move(newPacket));
// tell the sent packet history that we used a sequence number for an untracked packet
auto& sentPacketHistory = _sentPacketHistories[nodeUUID];
sentPacketHistory.untrackedPacketSent(sequence);
} else {
std::unique_ptr<NLPacket>& bufferedPacket = _pendingEditPackets[nodeUUID].first; //only a NLPacket for now