mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:24:00 +02:00
Merge pull request #11212 from howard-stearns/asynchronous-commerce-2
Asynchronous Ledger Interactions with Server
This commit is contained in:
commit
188cbee781
18 changed files with 143 additions and 169 deletions
|
@ -39,7 +39,7 @@ Item {
|
|||
width: parent.width
|
||||
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
|
||||
|
||||
profile: HFTabletWebEngineProfile;
|
||||
profile: HFWebEngineProfile;
|
||||
|
||||
property string userScriptUrl: ""
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ Item {
|
|||
width: parent.width
|
||||
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height
|
||||
|
||||
profile: HFTabletWebEngineProfile;
|
||||
profile: HFWebEngineProfile;
|
||||
|
||||
property string userScriptUrl: ""
|
||||
|
||||
|
|
|
@ -144,7 +144,7 @@ Item {
|
|||
width: parent.width
|
||||
height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height - web.headerHeight : parent.height - web.headerHeight
|
||||
anchors.top: buttons.bottom
|
||||
profile: HFTabletWebEngineProfile;
|
||||
profile: HFWebEngineProfile;
|
||||
|
||||
property string userScriptUrl: ""
|
||||
|
||||
|
@ -184,8 +184,6 @@ Item {
|
|||
webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||
});
|
||||
|
||||
webview.profile.httpUserAgent = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36";
|
||||
}
|
||||
|
||||
onFeaturePermissionRequested: {
|
||||
|
|
|
@ -73,7 +73,6 @@ Item {
|
|||
console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||
});
|
||||
|
||||
root.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface)";
|
||||
}
|
||||
|
||||
onFeaturePermissionRequested: {
|
||||
|
|
|
@ -147,7 +147,7 @@ Rectangle {
|
|||
width: parent.width;
|
||||
height: keyboardEnabled && keyboardRaised ? webViewHeight - keyboard.height : webViewHeight
|
||||
|
||||
profile: HFTabletWebEngineProfile;
|
||||
profile: HFWebEngineProfile;
|
||||
|
||||
property string userScriptUrl: ""
|
||||
|
||||
|
|
|
@ -35,8 +35,8 @@ Rectangle {
|
|||
Hifi.QmlCommerce {
|
||||
id: commerce;
|
||||
onBuyResult: {
|
||||
if (failureMessage.length) {
|
||||
buyButton.text = "Buy Failed";
|
||||
if (result.status !== 'success') {
|
||||
buyButton.text = result.message;
|
||||
buyButton.enabled = false;
|
||||
} else {
|
||||
if (urlHandler.canHandleUrl(itemHref)) {
|
||||
|
@ -46,20 +46,21 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
onBalanceResult: {
|
||||
if (failureMessage.length) {
|
||||
console.log("Failed to get balance", failureMessage);
|
||||
if (result.status !== 'success') {
|
||||
console.log("Failed to get balance", result.message);
|
||||
} else {
|
||||
balanceReceived = true;
|
||||
hfcBalanceText.text = balance;
|
||||
balanceAfterPurchase = balance - parseInt(itemPriceText.text, 10);
|
||||
hfcBalanceText.text = result.data.balance;
|
||||
balanceAfterPurchase = result.data.balance - parseInt(itemPriceText.text, 10);
|
||||
}
|
||||
}
|
||||
onInventoryResult: {
|
||||
if (failureMessage.length) {
|
||||
console.log("Failed to get inventory", failureMessage);
|
||||
if (result.status !== 'success') {
|
||||
console.log("Failed to get inventory", result.message);
|
||||
} else {
|
||||
inventoryReceived = true;
|
||||
if (inventoryContains(inventory.assets, itemId)) {
|
||||
console.log('inventory fixme', JSON.stringify(result));
|
||||
if (inventoryContains(result.data.assets, itemId)) {
|
||||
alreadyOwned = true;
|
||||
} else {
|
||||
alreadyOwned = false;
|
||||
|
|
|
@ -30,17 +30,17 @@ Rectangle {
|
|||
Hifi.QmlCommerce {
|
||||
id: commerce;
|
||||
onBalanceResult: {
|
||||
if (failureMessage.length) {
|
||||
console.log("Failed to get balance", failureMessage);
|
||||
if (result.status !== 'success') {
|
||||
console.log("Failed to get balance", result.message);
|
||||
} else {
|
||||
hfcBalanceText.text = balance;
|
||||
hfcBalanceText.text = result.data.balance;
|
||||
}
|
||||
}
|
||||
onInventoryResult: {
|
||||
if (failureMessage.length) {
|
||||
console.log("Failed to get inventory", failureMessage);
|
||||
if (result.status !== 'success') {
|
||||
console.log("Failed to get inventory", result.message);
|
||||
} else {
|
||||
inventoryContentsList.model = inventory.assets;
|
||||
inventoryContentsList.model = result.data.assets;
|
||||
}
|
||||
}
|
||||
onSecurityImageResult: {
|
||||
|
|
|
@ -10,72 +10,100 @@
|
|||
//
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include "AccountManager.h"
|
||||
#include "Wallet.h"
|
||||
#include "Ledger.h"
|
||||
#include "CommerceLogging.h"
|
||||
|
||||
// inventory answers {status: 'success', data: {assets: [{id: "guid", title: "name", preview: "url"}....]}}
|
||||
// balance answers {status: 'success', data: {balance: integer}}
|
||||
// buy and receive_at answer {status: 'success'}
|
||||
|
||||
QJsonObject Ledger::apiResponse(const QString& label, QNetworkReply& reply) {
|
||||
QByteArray response = reply.readAll();
|
||||
QJsonObject data = QJsonDocument::fromJson(response).object();
|
||||
qInfo(commerce) << label << "response" << QJsonDocument(data).toJson(QJsonDocument::Compact);
|
||||
return data;
|
||||
}
|
||||
// Non-200 responses are not json:
|
||||
QJsonObject Ledger::failResponse(const QString& label, QNetworkReply& reply) {
|
||||
QString response = reply.readAll();
|
||||
qWarning(commerce) << "FAILED" << label << response;
|
||||
QJsonObject result
|
||||
{
|
||||
{ "status", "fail" },
|
||||
{ "message", response }
|
||||
};
|
||||
return result;
|
||||
}
|
||||
#define ApiHandler(NAME) void Ledger::NAME##Success(QNetworkReply& reply) { emit NAME##Result(apiResponse(#NAME, reply)); }
|
||||
#define FailHandler(NAME) void Ledger::NAME##Failure(QNetworkReply& reply) { emit NAME##Result(failResponse(#NAME, reply)); }
|
||||
#define Handler(NAME) ApiHandler(NAME) FailHandler(NAME)
|
||||
Handler(buy)
|
||||
Handler(receiveAt)
|
||||
Handler(balance)
|
||||
Handler(inventory)
|
||||
|
||||
void Ledger::send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, QJsonObject request) {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
const QString URL = "/api/v1/commerce/";
|
||||
JSONCallbackParameters callbackParams(this, success, this, fail);
|
||||
qCInfo(commerce) << "Sending" << endpoint << QJsonDocument(request).toJson(QJsonDocument::Compact);
|
||||
accountManager->sendRequest(URL + endpoint,
|
||||
AccountManagerAuth::Required,
|
||||
method,
|
||||
callbackParams,
|
||||
QJsonDocument(request).toJson());
|
||||
}
|
||||
|
||||
void Ledger::signedSend(const QString& propertyName, const QByteArray& text, const QString& key, const QString& endpoint, const QString& success, const QString& fail) {
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
QString signature = key.isEmpty() ? "" : wallet->signWithKey(text, key);
|
||||
QJsonObject request;
|
||||
request[propertyName] = QString(text);
|
||||
request["signature"] = signature;
|
||||
send(endpoint, success, fail, QNetworkAccessManager::PutOperation, request);
|
||||
}
|
||||
|
||||
void Ledger::keysQuery(const QString& endpoint, const QString& success, const QString& fail) {
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
QJsonObject request;
|
||||
request["public_keys"] = QJsonArray::fromStringList(wallet->listPublicKeys());
|
||||
send(endpoint, success, fail, QNetworkAccessManager::PostOperation, request);
|
||||
}
|
||||
|
||||
void Ledger::buy(const QString& hfc_key, int cost, const QString& asset_id, const QString& inventory_key, const QString& buyerUsername) {
|
||||
QJsonObject transaction;
|
||||
transaction["hfc_key"] = hfc_key;
|
||||
transaction["hfc"] = cost;
|
||||
transaction["cost"] = cost;
|
||||
transaction["asset_id"] = asset_id;
|
||||
transaction["inventory_key"] = inventory_key;
|
||||
transaction["inventory_buyer_username"] = buyerUsername;
|
||||
QJsonDocument transactionDoc{ transaction };
|
||||
auto transactionString = transactionDoc.toJson(QJsonDocument::Compact);
|
||||
|
||||
auto wallet = DependencyManager::get<Wallet>();
|
||||
QString signature = wallet->signWithKey(transactionString, hfc_key);
|
||||
QJsonObject request;
|
||||
request["transaction"] = QString(transactionString);
|
||||
request["signature"] = signature;
|
||||
|
||||
qCInfo(commerce) << "Transaction:" << QJsonDocument(request).toJson(QJsonDocument::Compact);
|
||||
// FIXME: talk to server instead
|
||||
if (_inventory.contains(asset_id)) {
|
||||
// This is here more for testing than as a definition of semantics.
|
||||
// When we have popcerts, you will certainly be able to buy a new instance of an item that you already own a different instance of.
|
||||
// I'm not sure what the server should do for now in this project's MVP.
|
||||
return emit buyResult("Already owned.");
|
||||
}
|
||||
if (initializedBalance() < cost) {
|
||||
return emit buyResult("Insufficient funds.");
|
||||
}
|
||||
_balance -= cost;
|
||||
QJsonObject inventoryAdditionObject;
|
||||
inventoryAdditionObject["id"] = asset_id;
|
||||
inventoryAdditionObject["title"] = "Test Title";
|
||||
inventoryAdditionObject["preview"] = "https://www.aspca.org/sites/default/files/cat-care_cat-nutrition-tips_overweight_body4_left.jpg";
|
||||
_inventory.push_back(inventoryAdditionObject);
|
||||
emit buyResult("");
|
||||
signedSend("transaction", transactionString, hfc_key, "buy", "buySuccess", "buyFailure");
|
||||
}
|
||||
|
||||
bool Ledger::receiveAt(const QString& hfc_key) {
|
||||
bool Ledger::receiveAt(const QString& hfc_key, const QString& old_key) {
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
if (!accountManager->isLoggedIn()) {
|
||||
qCWarning(commerce) << "Cannot set receiveAt when not logged in.";
|
||||
emit receiveAtResult("Not logged in");
|
||||
QJsonObject result{ { "status", "fail" }, { "message", "Not logged in" } };
|
||||
emit receiveAtResult(result);
|
||||
return false; // We know right away that we will fail, so tell the caller.
|
||||
}
|
||||
auto username = accountManager->getAccountInfo().getUsername();
|
||||
qCInfo(commerce) << "Setting default receiving key for" << username;
|
||||
emit receiveAtResult(""); // FIXME: talk to server instead.
|
||||
|
||||
signedSend("public_key", hfc_key.toUtf8(), old_key, "receive_at", "receiveAtSuccess", "receiveAtFailure");
|
||||
return true; // Note that there may still be an asynchronous signal of failure that callers might be interested in.
|
||||
}
|
||||
|
||||
void Ledger::balance(const QStringList& keys) {
|
||||
// FIXME: talk to server instead
|
||||
qCInfo(commerce) << "Balance:" << initializedBalance();
|
||||
emit balanceResult(_balance, "");
|
||||
keysQuery("balance", "balanceSuccess", "balanceFailure");
|
||||
}
|
||||
|
||||
void Ledger::inventory(const QStringList& keys) {
|
||||
// FIXME: talk to server instead
|
||||
QJsonObject inventoryObject;
|
||||
inventoryObject.insert("success", true);
|
||||
inventoryObject.insert("assets", _inventory);
|
||||
qCInfo(commerce) << "Inventory:" << inventoryObject;
|
||||
emit inventoryResult(inventoryObject, "");
|
||||
keysQuery("inventory", "inventorySuccess", "inventoryFailure");
|
||||
}
|
||||
|
||||
|
|
|
@ -14,9 +14,10 @@
|
|||
#ifndef hifi_Ledger_h
|
||||
#define hifi_Ledger_h
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <DependencyManager.h>
|
||||
#include <qjsonobject.h>
|
||||
#include <qjsonarray.h>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
|
||||
|
||||
class Ledger : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
|
@ -24,21 +25,32 @@ class Ledger : public QObject, public Dependency {
|
|||
|
||||
public:
|
||||
void buy(const QString& hfc_key, int cost, const QString& asset_id, const QString& inventory_key, const QString& buyerUsername = "");
|
||||
bool receiveAt(const QString& hfc_key);
|
||||
bool receiveAt(const QString& hfc_key, const QString& old_key);
|
||||
void balance(const QStringList& keys);
|
||||
void inventory(const QStringList& keys);
|
||||
|
||||
signals:
|
||||
void buyResult(const QString& failureReason);
|
||||
void receiveAtResult(const QString& failureReason);
|
||||
void balanceResult(int balance, const QString& failureReason);
|
||||
void inventoryResult(QJsonObject inventory, const QString& failureReason);
|
||||
void buyResult(QJsonObject result);
|
||||
void receiveAtResult(QJsonObject result);
|
||||
void balanceResult(QJsonObject result);
|
||||
void inventoryResult(QJsonObject result);
|
||||
|
||||
public slots:
|
||||
void buySuccess(QNetworkReply& reply);
|
||||
void buyFailure(QNetworkReply& reply);
|
||||
void receiveAtSuccess(QNetworkReply& reply);
|
||||
void receiveAtFailure(QNetworkReply& reply);
|
||||
void balanceSuccess(QNetworkReply& reply);
|
||||
void balanceFailure(QNetworkReply& reply);
|
||||
void inventorySuccess(QNetworkReply& reply);
|
||||
void inventoryFailure(QNetworkReply& reply);
|
||||
|
||||
private:
|
||||
// These in-memory caches is temporary, until we start sending things to the server.
|
||||
int _balance{ -1 };
|
||||
QJsonArray _inventory{};
|
||||
int initializedBalance() { if (_balance < 0) _balance = 100; return _balance; }
|
||||
QJsonObject apiResponse(const QString& label, QNetworkReply& reply);
|
||||
QJsonObject failResponse(const QString& label, QNetworkReply& reply);
|
||||
void send(const QString& endpoint, const QString& success, const QString& fail, QNetworkAccessManager::Operation method, QJsonObject request);
|
||||
void keysQuery(const QString& endpoint, const QString& success, const QString& fail);
|
||||
void signedSend(const QString& propertyName, const QByteArray& text, const QString& key, const QString& endpoint, const QString& success, const QString& fail);
|
||||
};
|
||||
|
||||
#endif // hifi_Ledger_h
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Commerce.cpp
|
||||
// QmlCommerce.cpp
|
||||
// interface/src/commerce
|
||||
//
|
||||
// Created by Howard Stearns on 8/4/17.
|
||||
|
@ -31,14 +31,12 @@ void QmlCommerce::buy(const QString& assetId, int cost, const QString& buyerUser
|
|||
auto wallet = DependencyManager::get<Wallet>();
|
||||
QStringList keys = wallet->listPublicKeys();
|
||||
if (keys.count() == 0) {
|
||||
return emit buyResult("Uninitialized Wallet.");
|
||||
QJsonObject result{ { "status", "fail" }, { "message", "Uninitialized Wallet." } };
|
||||
return emit buyResult(result);
|
||||
}
|
||||
QString key = keys[0];
|
||||
// For now, we receive at the same key that pays for it.
|
||||
ledger->buy(key, cost, assetId, key, buyerUsername);
|
||||
// FIXME: until we start talking to server, report post-transaction balance and inventory so we can see log for testing.
|
||||
balance();
|
||||
inventory();
|
||||
}
|
||||
|
||||
void QmlCommerce::balance() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Commerce.h
|
||||
// QmlCommerce.h
|
||||
// interface/src/commerce
|
||||
//
|
||||
// Guard for safe use of Commerce (Wallet, Ledger) by authorized QML.
|
||||
|
@ -15,6 +15,7 @@
|
|||
#ifndef hifi_QmlCommerce_h
|
||||
#define hifi_QmlCommerce_h
|
||||
|
||||
#include <QJsonObject>
|
||||
#include <OffscreenQmlDialog.h>
|
||||
|
||||
class QmlCommerce : public OffscreenQmlDialog {
|
||||
|
@ -25,11 +26,11 @@ public:
|
|||
QmlCommerce(QQuickItem* parent = nullptr);
|
||||
|
||||
signals:
|
||||
void buyResult(const QString& failureMessage);
|
||||
void buyResult(QJsonObject result);
|
||||
// Balance and Inventory are NOT properties, because QML can't change them (without risk of failure), and
|
||||
// because we can't scalably know of out-of-band changes (e.g., another machine interacting with the block chain).
|
||||
void balanceResult(int balance, const QString& failureMessage);
|
||||
void inventoryResult(QJsonObject inventory, const QString& failureMessage);
|
||||
void balanceResult(QJsonObject result);
|
||||
void inventoryResult(QJsonObject result);
|
||||
void securityImageResult(uint imageID);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -205,7 +205,7 @@ bool Wallet::createIfNeeded() {
|
|||
qCDebug(commerce) << "read private key";
|
||||
RSA_free(key);
|
||||
// K -- add the public key since we have a legit private key associated with it
|
||||
_publicKeys.push_back(QUrl::toPercentEncoding(publicKey.toBase64()));
|
||||
_publicKeys.push_back(publicKey.toBase64());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -216,16 +216,17 @@ bool Wallet::createIfNeeded() {
|
|||
bool Wallet::generateKeyPair() {
|
||||
qCInfo(commerce) << "Generating keypair.";
|
||||
auto keyPair = generateRSAKeypair();
|
||||
|
||||
_publicKeys.push_back(QUrl::toPercentEncoding(keyPair.first->toBase64()));
|
||||
qCDebug(commerce) << "public key:" << _publicKeys.last();
|
||||
QString oldKey = _publicKeys.count() == 0 ? "" : _publicKeys.last();
|
||||
QString key = keyPair.first->toBase64();
|
||||
_publicKeys.push_back(key);
|
||||
qCDebug(commerce) << "public key:" << key;
|
||||
|
||||
// It's arguable whether we want to change the receiveAt every time, but:
|
||||
// 1. It's certainly needed the first time, when createIfNeeded answers true.
|
||||
// 2. It is maximally private, and we can step back from that later if desired.
|
||||
// 3. It maximally exercises all the machinery, so we are most likely to surface issues now.
|
||||
auto ledger = DependencyManager::get<Ledger>();
|
||||
return ledger->receiveAt(_publicKeys.last());
|
||||
return ledger->receiveAt(key, oldKey);
|
||||
}
|
||||
QStringList Wallet::listPublicKeys() {
|
||||
qCInfo(commerce) << "Enumerating public keys.";
|
||||
|
@ -260,7 +261,7 @@ QString Wallet::signWithKey(const QByteArray& text, const QString& key) {
|
|||
RSA_free(rsaPrivateKey);
|
||||
|
||||
if (encryptReturn != -1) {
|
||||
return QUrl::toPercentEncoding(signature.toBase64());
|
||||
return signature.toBase64();
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
|
|
|
@ -43,7 +43,6 @@
|
|||
|
||||
#include "types/FileTypeProfile.h"
|
||||
#include "types/HFWebEngineProfile.h"
|
||||
#include "types/HFTabletWebEngineProfile.h"
|
||||
#include "types/SoundEffect.h"
|
||||
|
||||
#include "Logging.h"
|
||||
|
@ -328,7 +327,6 @@ void initializeQmlEngine(QQmlEngine* engine, QQuickWindow* window) {
|
|||
}
|
||||
rootContext->setContextProperty("FileTypeProfile", new FileTypeProfile(rootContext));
|
||||
rootContext->setContextProperty("HFWebEngineProfile", new HFWebEngineProfile(rootContext));
|
||||
rootContext->setContextProperty("HFTabletWebEngineProfile", new HFTabletWebEngineProfile(rootContext));
|
||||
rootContext->setContextProperty("Paths", DependencyManager::get<PathUtils>().data());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
//
|
||||
// HFTabletWebEngineProfile.h
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Dante Ruiz on 2017-03-31.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "HFTabletWebEngineProfile.h"
|
||||
#include "HFTabletWebEngineRequestInterceptor.h"
|
||||
|
||||
static const QString QML_WEB_ENGINE_NAME = "qmlTabletWebEngine";
|
||||
|
||||
HFTabletWebEngineProfile::HFTabletWebEngineProfile(QObject* parent) : QQuickWebEngineProfile(parent) {
|
||||
|
||||
static const QString WEB_ENGINE_USER_AGENT = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36";
|
||||
|
||||
setHttpUserAgent(WEB_ENGINE_USER_AGENT);
|
||||
setStorageName(QML_WEB_ENGINE_NAME);
|
||||
|
||||
auto requestInterceptor = new HFTabletWebEngineRequestInterceptor(this);
|
||||
setRequestInterceptor(requestInterceptor);
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
//
|
||||
// HFTabletWebEngineRequestInterceptor.cpp
|
||||
// interface/src/networking
|
||||
//
|
||||
// Created by Dante Ruiz on 2017-3-31.
|
||||
// Copyright 2017 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "HFTabletWebEngineRequestInterceptor.h"
|
||||
#include <QtCore/QDebug>
|
||||
#include "AccountManager.h"
|
||||
|
||||
bool isTabletAuthableHighFidelityURL(const QUrl& url) {
|
||||
static const QStringList HF_HOSTS = {
|
||||
"highfidelity.com", "highfidelity.io",
|
||||
"metaverse.highfidelity.com", "metaverse.highfidelity.io"
|
||||
};
|
||||
|
||||
return url.scheme() == "https" && HF_HOSTS.contains(url.host());
|
||||
}
|
||||
|
||||
void HFTabletWebEngineRequestInterceptor::interceptRequest(QWebEngineUrlRequestInfo& info) {
|
||||
// check if this is a request to a highfidelity URL
|
||||
if (isTabletAuthableHighFidelityURL(info.requestUrl())) {
|
||||
// if we have an access token, add it to the right HTTP header for authorization
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
||||
if (accountManager->hasValidAccessToken()) {
|
||||
static const QString OAUTH_AUTHORIZATION_HEADER = "Authorization";
|
||||
|
||||
QString bearerTokenString = "Bearer " + accountManager->getAccountInfo().getAccessToken().token;
|
||||
info.setHttpHeader(OAUTH_AUTHORIZATION_HEADER.toLocal8Bit(), bearerTokenString.toLocal8Bit());
|
||||
}
|
||||
|
||||
static const QString USER_AGENT = "User-Agent";
|
||||
QString tokenString = "Chrome/48.0 (HighFidelityInterface)";
|
||||
info.setHttpHeader(USER_AGENT.toLocal8Bit(), tokenString.toLocal8Bit());
|
||||
} else {
|
||||
static const QString USER_AGENT = "User-Agent";
|
||||
QString tokenString = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36";
|
||||
info.setHttpHeader(USER_AGENT.toLocal8Bit(), tokenString.toLocal8Bit());
|
||||
}
|
||||
}
|
|
@ -18,8 +18,6 @@ static const QString QML_WEB_ENGINE_STORAGE_NAME = "qmlWebEngine";
|
|||
HFWebEngineProfile::HFWebEngineProfile(QObject* parent) :
|
||||
QQuickWebEngineProfile(parent)
|
||||
{
|
||||
static const QString WEB_ENGINE_USER_AGENT = "Chrome/48.0 (HighFidelityInterface)";
|
||||
setHttpUserAgent(WEB_ENGINE_USER_AGENT);
|
||||
setStorageName(QML_WEB_ENGINE_STORAGE_NAME);
|
||||
|
||||
// we use the HFWebEngineRequestInterceptor to make sure that web requests are authenticated for the interface user
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "NetworkingConstants.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <SettingHandle.h>
|
||||
|
||||
#include "AccountManager.h"
|
||||
|
||||
|
@ -42,7 +43,8 @@ namespace {
|
|||
|
||||
void RequestFilters::interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info) {
|
||||
// check if this is a request to a highfidelity URL
|
||||
if (isAuthableHighFidelityURL(info.requestUrl())) {
|
||||
bool isAuthable = isAuthableHighFidelityURL(info.requestUrl());
|
||||
if (isAuthable) {
|
||||
// if we have an access token, add it to the right HTTP header for authorization
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
|
||||
|
@ -53,6 +55,17 @@ void RequestFilters::interceptHFWebEngineRequest(QWebEngineUrlRequestInfo& info)
|
|||
info.setHttpHeader(OAUTH_AUTHORIZATION_HEADER.toLocal8Bit(), bearerTokenString.toLocal8Bit());
|
||||
}
|
||||
}
|
||||
static const QString USER_AGENT = "User-Agent";
|
||||
const QString tokenStringMobile{ "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36" };
|
||||
const QString tokenStringMetaverse{ "Chrome/48.0 (HighFidelityInterface)" };
|
||||
|
||||
// During the period in which we have HFC commerce in the system, but not applied everywhere:
|
||||
const QString tokenStringCommerce{ "Chrome/48.0 (HighFidelityInterface WithHFC)" };
|
||||
static Setting::Handle<bool> _settingSwitch{ "inspectionMode", false };
|
||||
bool isMoney = _settingSwitch.get();
|
||||
|
||||
const QString tokenString = !isAuthable ? tokenStringMobile : (isMoney ? tokenStringCommerce : tokenStringMetaverse);
|
||||
info.setHttpHeader(USER_AGENT.toLocal8Bit(), tokenString.toLocal8Bit());
|
||||
}
|
||||
|
||||
void RequestFilters::interceptFileType(QWebEngineUrlRequestInfo& info) {
|
||||
|
|
|
@ -115,7 +115,7 @@
|
|||
itemId: id,
|
||||
itemName: name,
|
||||
itemAuthor: author,
|
||||
itemPrice: Math.round(Math.random() * 50),
|
||||
itemPrice: price ? parseInt(price, 10) : Math.round(Math.random() * 50),
|
||||
itemHref: href
|
||||
}));
|
||||
}
|
||||
|
@ -130,7 +130,7 @@
|
|||
buyButtonClicked($(this).closest('.grid-item').attr('data-item-id'),
|
||||
$(this).closest('.grid-item').find('.item-title').text(),
|
||||
$(this).closest('.grid-item').find('.creator').find('.value').text(),
|
||||
10,
|
||||
$(this).closest('.grid-item').find('.item-cost').text(),
|
||||
$(this).attr('data-href'));
|
||||
});
|
||||
}
|
||||
|
@ -166,7 +166,7 @@
|
|||
buyButtonClicked(window.location.pathname.split("/")[3],
|
||||
$('#top-center').find('h1').text(),
|
||||
$('#creator').find('.value').text(),
|
||||
10,
|
||||
$('.item-cost').text(),
|
||||
href);
|
||||
});
|
||||
addInventoryButton();
|
||||
|
|
Loading…
Reference in a new issue