mirror of
https://github.com/moonlight-stream/moonlight-chrome.git
synced 2025-08-17 08:36:42 +00:00
Require cert pinning for HTTPS
This commit is contained in:
parent
ecad4aa276
commit
0ddf07f4de
12
http.cpp
12
http.cpp
@ -97,9 +97,14 @@ void MoonlightInstance::NvHTTPInit(int32_t callbackId, pp::VarArray args)
|
||||
PostMessage(ret);
|
||||
}
|
||||
|
||||
void MoonlightInstance::NvHTTPRequest(int32_t /*result*/, int32_t callbackId, std::string url, bool binaryResponse)
|
||||
void MoonlightInstance::NvHTTPRequest(int32_t /*result*/, int32_t callbackId, pp::VarArray args)
|
||||
{
|
||||
char* _url = strdup(url.c_str());
|
||||
std::string url = args.Get(0).AsString();
|
||||
std::string ppkstr = args.Get(1).AsString();
|
||||
bool binaryResponse = args.Get(2).AsBool();
|
||||
|
||||
PostMessage(pp::Var(url.c_str()));
|
||||
|
||||
PHTTP_DATA data = http_create_data();
|
||||
int err;
|
||||
|
||||
@ -112,7 +117,7 @@ void MoonlightInstance::NvHTTPRequest(int32_t /*result*/, int32_t callbackId, st
|
||||
goto clean_data;
|
||||
}
|
||||
|
||||
err = http_request(_url , data);
|
||||
err = http_request(url.c_str(), ppkstr.c_str(), data);
|
||||
if (err) {
|
||||
pp::VarDictionary ret;
|
||||
ret.Set("callbackId", pp::Var(callbackId));
|
||||
@ -148,5 +153,4 @@ void MoonlightInstance::NvHTTPRequest(int32_t /*result*/, int32_t callbackId, st
|
||||
|
||||
clean_data:
|
||||
http_free_data(data);
|
||||
free(_url);
|
||||
}
|
||||
|
@ -27,3 +27,4 @@
|
||||
#define GS_IO_ERROR -5
|
||||
#define GS_NOT_SUPPORTED_4K -6
|
||||
|
||||
#define GS_CERT_MISMATCH -100
|
||||
|
@ -59,7 +59,7 @@ static CURLcode sslctx_function(CURL * curl, void * sslctx, void * parm)
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
int http_request(char* url, PHTTP_DATA data) {
|
||||
int http_request(const char* url, const char* ppkstr, PHTTP_DATA data) {
|
||||
int ret;
|
||||
CURL *curl;
|
||||
|
||||
@ -67,12 +67,10 @@ int http_request(char* url, PHTTP_DATA data) {
|
||||
if (!curl)
|
||||
return GS_FAILED;
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE,"PEM");
|
||||
curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _write_curl);
|
||||
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, *sslctx_function);
|
||||
@ -86,8 +84,12 @@ int http_request(char* url, PHTTP_DATA data) {
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, data);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
|
||||
// HACK: Connecting with TLS v1.2 causes unexpected TLS alerts
|
||||
curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1);
|
||||
// Use the pinned certificate for HTTPS
|
||||
if (ppkstr != NULL) {
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
curl_easy_setopt(curl, CURLOPT_PINNEDPUBLICKEY, ppkstr);
|
||||
}
|
||||
|
||||
if (data->size > 0) {
|
||||
free(data->memory);
|
||||
@ -102,7 +104,9 @@ int http_request(char* url, PHTTP_DATA data) {
|
||||
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
|
||||
if(res != CURLE_OK) {
|
||||
if (res == CURLE_SSL_PINNEDPUBKEYNOTMATCH) {
|
||||
ret = GS_CERT_MISMATCH;
|
||||
} else if (res != CURLE_OK) {
|
||||
ret = GS_FAILED;
|
||||
} else if (data->memory == NULL) {
|
||||
ret = GS_OUT_OF_MEMORY;
|
||||
|
@ -31,7 +31,7 @@ typedef struct _HTTP_DATA {
|
||||
} HTTP_DATA, *PHTTP_DATA;
|
||||
|
||||
PHTTP_DATA http_create_data();
|
||||
int http_request(char* url, PHTTP_DATA data);
|
||||
int http_request(const char* url, const char* ppkstr, PHTTP_DATA data);
|
||||
void http_free_data(PHTTP_DATA data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -54,11 +54,13 @@ static int xml_search(char* data, size_t len, char* node, char** result) {
|
||||
|
||||
startOffset = strstr(data, startTag);
|
||||
if (startOffset == NULL) {
|
||||
free(data);
|
||||
return GS_FAILED;
|
||||
}
|
||||
|
||||
endOffset = strstr(data, endTag);
|
||||
if (endOffset == NULL) {
|
||||
free(data);
|
||||
return GS_FAILED;
|
||||
}
|
||||
|
||||
@ -67,6 +69,7 @@ static int xml_search(char* data, size_t len, char* node, char** result) {
|
||||
*result = malloc(strlen(startOffset + strlen(startTag)) + 1);
|
||||
strcpy(*result, startOffset + strlen(startTag));
|
||||
|
||||
free(data);
|
||||
return GS_OK;
|
||||
}
|
||||
|
||||
@ -141,24 +144,73 @@ static bool verifySignature(const unsigned char *data, int dataLength, unsigned
|
||||
}
|
||||
|
||||
X509* get_cert(PHTTP_DATA data) {
|
||||
char *result;
|
||||
char *pemcerthex;
|
||||
|
||||
if (xml_search(data->memory, data->size, "plaincert", &result) != GS_OK)
|
||||
if (xml_search(data->memory, data->size, "plaincert", &pemcerthex) != GS_OK)
|
||||
return NULL;
|
||||
|
||||
BIO* bio = BIO_new_mem_buf(result, -1);
|
||||
free(result);
|
||||
// Convert cert from hex string to the PEM string and null terminate
|
||||
int hexstrlen = strlen(pemcerthex);
|
||||
char *pemcert = malloc(hexstrlen / 2 + 1);
|
||||
for (int count = 0; count < hexstrlen; count += 2) {
|
||||
sscanf(&pemcerthex[count], "%2hhx", &pemcert[count / 2]);
|
||||
}
|
||||
pemcert[hexstrlen / 2] = 0;
|
||||
free(pemcerthex);
|
||||
|
||||
// pemcert is referenced, but NOT copied!
|
||||
BIO* bio = BIO_new_mem_buf(pemcert, -1);
|
||||
|
||||
if (bio) {
|
||||
X509* cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
||||
BIO_free_all(bio);
|
||||
free(pemcert);
|
||||
return cert;
|
||||
}
|
||||
else {
|
||||
free(pemcert);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static char* x509_to_curl_ppk_string(X509* x509) {
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
|
||||
// Get x509 public key alone in DER format
|
||||
EVP_PKEY* pubkey = X509_get_pubkey(x509);
|
||||
i2d_PUBKEY_bio(bio, pubkey);
|
||||
EVP_PKEY_free(pubkey);
|
||||
|
||||
BUF_MEM* mem;
|
||||
BIO_get_mem_ptr(bio, &mem);
|
||||
|
||||
// SHA256 hash the resulting DER string
|
||||
unsigned char pubkeyhash[32];
|
||||
SHA256((unsigned char*)mem->data, mem->length, pubkeyhash);
|
||||
BIO_free(bio);
|
||||
|
||||
// Base64-encode the resulting SHA256 hash
|
||||
bio = BIO_new(BIO_s_mem());
|
||||
BIO* b64 = BIO_new(BIO_f_base64());
|
||||
bio = BIO_push(b64, bio);
|
||||
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
|
||||
BIO_write(bio, pubkeyhash, sizeof(pubkeyhash));
|
||||
BIO_flush(bio);
|
||||
|
||||
BIO_get_mem_ptr(bio, &mem);
|
||||
|
||||
// Assemble the final curl PPK string
|
||||
const char* prefix = "sha256//";
|
||||
char* ret = malloc(strlen(prefix) + mem->length + 1);
|
||||
memcpy(ret, prefix, strlen(prefix));
|
||||
memcpy(&ret[strlen(prefix)], mem->data, mem->length);
|
||||
ret[strlen(prefix) + mem->length] = 0;
|
||||
|
||||
BIO_free_all(bio);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gs_unpair(const char* address) {
|
||||
int ret = GS_OK;
|
||||
char url[4096];
|
||||
@ -167,13 +219,13 @@ int gs_unpair(const char* address) {
|
||||
return GS_OUT_OF_MEMORY;
|
||||
|
||||
snprintf(url, sizeof(url), "http://%s:47989/unpair?uniqueid=%s", address, g_UniqueId);
|
||||
ret = http_request(url, data);
|
||||
ret = http_request(url, NULL, data);
|
||||
|
||||
http_free_data(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gs_pair(int serverMajorVersion, const char* address, const char* pin) {
|
||||
int gs_pair(int serverMajorVersion, const char* address, const char* pin, char** curl_ppk_string) {
|
||||
int ret = GS_OK;
|
||||
char* result = NULL;
|
||||
X509* server_cert = NULL;
|
||||
@ -188,7 +240,7 @@ int gs_pair(int serverMajorVersion, const char* address, const char* pin) {
|
||||
PHTTP_DATA data = http_create_data();
|
||||
if (data == NULL)
|
||||
return GS_OUT_OF_MEMORY;
|
||||
else if ((ret = http_request(url, data)) != GS_OK)
|
||||
else if ((ret = http_request(url, NULL, data)) != GS_OK)
|
||||
goto cleanup;
|
||||
|
||||
if ((ret = xml_search(data->memory, data->size, "paired", &result)) != GS_OK)
|
||||
@ -230,7 +282,7 @@ int gs_pair(int serverMajorVersion, const char* address, const char* pin) {
|
||||
bytes_to_hex(challenge_enc, challenge_hex, 16);
|
||||
|
||||
snprintf(url, sizeof(url), "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&clientchallenge=%s", address, g_UniqueId, challenge_hex);
|
||||
if ((ret = http_request(url, data)) != GS_OK)
|
||||
if ((ret = http_request(url, NULL, data)) != GS_OK)
|
||||
goto cleanup;
|
||||
|
||||
free(result);
|
||||
@ -284,7 +336,7 @@ int gs_pair(int serverMajorVersion, const char* address, const char* pin) {
|
||||
bytes_to_hex(challenge_response_hash_enc, challenge_response_hex, 32);
|
||||
|
||||
snprintf(url, sizeof(url), "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&serverchallengeresp=%s", address, g_UniqueId, challenge_response_hex);
|
||||
if ((ret = http_request(url, data)) != GS_OK)
|
||||
if ((ret = http_request(url, NULL, data)) != GS_OK)
|
||||
goto cleanup;
|
||||
|
||||
free(result);
|
||||
@ -328,7 +380,7 @@ int gs_pair(int serverMajorVersion, const char* address, const char* pin) {
|
||||
bytes_to_hex(client_pairing_secret, client_pairing_secret_hex, 16 + 256);
|
||||
|
||||
snprintf(url, sizeof(url), "http://%s:47989/pair?uniqueid=%s&devicename=roth&updateState=1&clientpairingsecret=%s", address, g_UniqueId, client_pairing_secret_hex);
|
||||
if ((ret = http_request(url, data)) != GS_OK)
|
||||
if ((ret = http_request(url, NULL, data)) != GS_OK)
|
||||
goto cleanup;
|
||||
|
||||
free(result);
|
||||
@ -341,6 +393,8 @@ int gs_pair(int serverMajorVersion, const char* address, const char* pin) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*curl_ppk_string = x509_to_curl_ppk_string(server_cert);
|
||||
|
||||
cleanup:
|
||||
if (ret != GS_OK)
|
||||
gs_unpair(address);
|
||||
|
@ -23,7 +23,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int gs_pair(int serverMajorVersion, const char* address, const char* pin);
|
||||
int gs_pair(int serverMajorVersion, const char* address, const char* pin, char** server_cert_der_string);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
18
main.cpp
18
main.cpp
@ -257,13 +257,8 @@ void MoonlightInstance::HandleStopStream(int32_t callbackId, pp::VarArray args)
|
||||
}
|
||||
|
||||
void MoonlightInstance::HandleOpenURL(int32_t callbackId, pp::VarArray args) {
|
||||
std::string url = args.Get(0).AsString();
|
||||
bool binaryResponse = args.Get(1).AsBool();
|
||||
|
||||
m_HttpThreadPool[m_HttpThreadPoolSequence++ % HTTP_HANDLER_THREADS]->message_loop().PostWork(
|
||||
m_CallbackFactory.NewCallback(&MoonlightInstance::NvHTTPRequest, callbackId, url, binaryResponse));
|
||||
|
||||
PostMessage(pp::Var (url.c_str()));
|
||||
m_CallbackFactory.NewCallback(&MoonlightInstance::NvHTTPRequest, callbackId, args));
|
||||
}
|
||||
|
||||
void MoonlightInstance::HandlePair(int32_t callbackId, pp::VarArray args) {
|
||||
@ -272,12 +267,21 @@ void MoonlightInstance::HandlePair(int32_t callbackId, pp::VarArray args) {
|
||||
}
|
||||
|
||||
void MoonlightInstance::PairCallback(int32_t /*result*/, int32_t callbackId, pp::VarArray args) {
|
||||
int err = gs_pair(atoi(args.Get(0).AsString().c_str()), args.Get(1).AsString().c_str(), args.Get(2).AsString().c_str());
|
||||
char* ppkstr;
|
||||
int err = gs_pair(atoi(args.Get(0).AsString().c_str()), args.Get(1).AsString().c_str(), args.Get(2).AsString().c_str(), &ppkstr);
|
||||
|
||||
pp::VarDictionary ret;
|
||||
ret.Set("callbackId", pp::Var(callbackId));
|
||||
if (err == 0) {
|
||||
ret.Set("type", pp::Var("resolve"));
|
||||
ret.Set("ret", pp::Var(ppkstr));
|
||||
free(ppkstr);
|
||||
}
|
||||
else {
|
||||
ret.Set("type", pp::Var("reject"));
|
||||
ret.Set("ret", pp::Var(err));
|
||||
}
|
||||
|
||||
PostMessage(ret);
|
||||
}
|
||||
|
||||
|
@ -156,7 +156,7 @@ class MoonlightInstance : public pp::Instance, public pp::MouseLock {
|
||||
void LoadCert(const char* certStr, const char* keyStr);
|
||||
|
||||
void NvHTTPInit(int32_t callbackId, pp::VarArray args);
|
||||
void NvHTTPRequest(int32_t, int32_t callbackId, std::string url, bool binaryResponse);
|
||||
void NvHTTPRequest(int32_t, int32_t callbackId, pp::VarArray args);
|
||||
|
||||
private:
|
||||
static CONNECTION_LISTENER_CALLBACKS s_ClCallbacks;
|
||||
|
@ -237,6 +237,7 @@ function moduleDidLoad() {
|
||||
revivedHost.serverUid = hosts[hostUID].serverUid;
|
||||
revivedHost.externalIP = hosts[hostUID].externalIP;
|
||||
revivedHost.hostname = hosts[hostUID].hostname;
|
||||
revivedHost.ppkstr = hosts[hostUID].ppkstr;
|
||||
addHostToGrid(revivedHost);
|
||||
}
|
||||
console.log('%c[index.js]', 'color: green;', 'Loaded previously connected hosts');
|
||||
@ -277,9 +278,13 @@ function pairTo(nvhttpHost, onSuccess, onFailure) {
|
||||
pairingDialog.close();
|
||||
});
|
||||
|
||||
console.log('%c[index.js]', 'color: green;', 'Sending pairing request to ' + nvhttpHost.hostname + ' with random number' + randomNumber);
|
||||
nvhttpHost.pair(randomNumber).then(function(paired) {
|
||||
if (!paired) {
|
||||
console.log('%c[index.js]', 'color: green;', 'Sending pairing request to ' + nvhttpHost.hostname + ' with PIN: ' + randomNumber);
|
||||
nvhttpHost.pair(randomNumber).then(function() {
|
||||
snackbarLog('Pairing successful');
|
||||
pairingDialog.close();
|
||||
onSuccess();
|
||||
}, function(failedPairing) {
|
||||
snackbarLog('Failed pairing to: ' + nvhttpHost.hostname);
|
||||
if (nvhttpHost.currentGame != 0) {
|
||||
$('#pairingDialogText').html('Error: ' + nvhttpHost.hostname + ' is busy. Stop streaming to pair.');
|
||||
} else {
|
||||
@ -287,17 +292,6 @@ function pairTo(nvhttpHost, onSuccess, onFailure) {
|
||||
}
|
||||
console.log('%c[index.js]', 'color: green;', 'Failed API object:', nvhttpHost, nvhttpHost.toString()); //Logging both the object and the toString version for text logs
|
||||
onFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
snackbarLog('Pairing successful');
|
||||
pairingDialog.close();
|
||||
onSuccess();
|
||||
}, function(failedPairing) {
|
||||
snackbarLog('Failed pairing to: ' + nvhttpHost.hostname);
|
||||
console.error('%c[index.js]', 'color: green;', 'Pairing failed, and returned:', failedPairing);
|
||||
console.error('%c[index.js]', 'color: green;', 'Failed API object:', nvhttpHost, nvhttpHost.toString()); //Logging both the object and the toString version for text logs
|
||||
onFailure();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ String.prototype.toHex = function() {
|
||||
function NvHTTP(address, clientUid, userEnteredAddress = '') {
|
||||
console.log('%c[utils.js, NvHTTP Object]', 'color: gray;', this);
|
||||
this.address = address;
|
||||
this.ppkstr = null;
|
||||
this.paired = false;
|
||||
this.currentGame = 0;
|
||||
this.serverMajorVersion = 0;
|
||||
@ -111,11 +112,26 @@ function _base64ToArrayBuffer(base64) {
|
||||
|
||||
NvHTTP.prototype = {
|
||||
refreshServerInfo: function() {
|
||||
if (this.ppkstr == null) {
|
||||
return sendMessage('openUrl', [this._baseUrlHttp + '/serverinfo?' + this._buildUidStr(), this.ppkstr, false]).then(function(retHttp) {
|
||||
this._parseServerInfo(retHttp);
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
// try HTTPS first
|
||||
return sendMessage('openUrl', [this._baseUrlHttps + '/serverinfo?' + this._buildUidStr(), false]).then(function(ret) {
|
||||
return sendMessage('openUrl', [this._baseUrlHttps + '/serverinfo?' + this._buildUidStr(), this.ppkstr, false]).then(function(ret) {
|
||||
if (!this._parseServerInfo(ret)) { // if that fails
|
||||
// try HTTP as a failover. Useful to clients who aren't paired yet
|
||||
return sendMessage('openUrl', [this._baseUrlHttp + '/serverinfo?' + this._buildUidStr(), false]).then(function(retHttp) {
|
||||
return sendMessage('openUrl', [this._baseUrlHttp + '/serverinfo?' + this._buildUidStr(), this.ppkstr, false]).then(function(retHttp) {
|
||||
this._parseServerInfo(retHttp);
|
||||
}.bind(this));
|
||||
}
|
||||
}.bind(this),
|
||||
function(error) {
|
||||
if (error == -100) { // GS_CERT_MISMATCH
|
||||
// Retry over HTTP
|
||||
console.warn('%c[utils.js, utils.js, refreshServerInfo]', 'color: gray;', 'Certificate mismatch. Retrying over HTTP', this);
|
||||
return sendMessage('openUrl', [this._baseUrlHttp + '/serverinfo?' + this._buildUidStr(), this.ppkstr, false]).then(function(retHttp) {
|
||||
this._parseServerInfo(retHttp);
|
||||
}.bind(this));
|
||||
}
|
||||
@ -124,12 +140,28 @@ NvHTTP.prototype = {
|
||||
|
||||
// refreshes the server info using a given address. This is useful for testing whether we can successfully ping a host at a given address
|
||||
refreshServerInfoAtAddress: function(givenAddress) {
|
||||
if (this.ppkstr == null) {
|
||||
// Use HTTP if we have no pinned cert
|
||||
return sendMessage('openUrl', ['http://' + givenAddress + ':47989' + '/serverinfo?' + this._buildUidStr(), this.ppkstr, false]).then(function(retHttp) {
|
||||
return this._parseServerInfo(retHttp);
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
// try HTTPS first
|
||||
return sendMessage('openUrl', ['https://' + givenAddress + ':47984' + '/serverinfo?' + this._buildUidStr(), false]).then(function(ret) {
|
||||
return sendMessage('openUrl', ['https://' + givenAddress + ':47984' + '/serverinfo?' + this._buildUidStr(), this.ppkstr, false]).then(function(ret) {
|
||||
if (!this._parseServerInfo(ret)) { // if that fails
|
||||
console.log('%c[utils.js, utils.js, refreshServerInfoAtAddress]', 'color: gray;', 'Failed to parse serverinfo from HTTPS, falling back to HTTP');
|
||||
// try HTTP as a failover. Useful to clients who aren't paired yet
|
||||
return sendMessage('openUrl', ['http://' + givenAddress + ':47989' + '/serverinfo?' + this._buildUidStr(), false]).then(function(retHttp) {
|
||||
return sendMessage('openUrl', ['http://' + givenAddress + ':47989' + '/serverinfo?' + this._buildUidStr(), this.ppkstr, false]).then(function(retHttp) {
|
||||
return this._parseServerInfo(retHttp);
|
||||
}.bind(this));
|
||||
}
|
||||
}.bind(this),
|
||||
function(error) {
|
||||
if (error == -100) { // GS_CERT_MISMATCH
|
||||
// Retry over HTTP
|
||||
console.warn('%c[utils.js, utils.js, refreshServerInfoAtAddress]', 'color: gray;', 'Certificate mismatch. Retrying over HTTP', this);
|
||||
return sendMessage('openUrl', ['http://' + givenAddress + ':47989' + '/serverinfo?' + this._buildUidStr(), this.ppkstr, false]).then(function(retHttp) {
|
||||
return this._parseServerInfo(retHttp);
|
||||
}.bind(this));
|
||||
}
|
||||
@ -157,7 +189,7 @@ NvHTTP.prototype = {
|
||||
// Poll for the app list every 10 successful serverinfo polls.
|
||||
// Not including the first one to avoid PCs taking a while to show
|
||||
// as online initially
|
||||
if (this._pollCount++ % 10 == 1) {
|
||||
if (this.paired && this._pollCount++ % 10 == 1) {
|
||||
this.getAppListWithCacheFlush();
|
||||
}
|
||||
|
||||
@ -318,7 +350,7 @@ NvHTTP.prototype = {
|
||||
},
|
||||
|
||||
getAppListWithCacheFlush: function() {
|
||||
return sendMessage('openUrl', [this._baseUrlHttps + '/applist?' + this._buildUidStr(), false]).then(function(ret) {
|
||||
return sendMessage('openUrl', [this._baseUrlHttps + '/applist?' + this._buildUidStr(), this.ppkstr, false]).then(function(ret) {
|
||||
$xml = this._parseXML(ret);
|
||||
$root = $xml.find("root");
|
||||
|
||||
@ -377,6 +409,7 @@ NvHTTP.prototype = {
|
||||
'/appasset?' + this._buildUidStr() +
|
||||
'&appid=' + appId +
|
||||
'&AssetType=2&AssetIdx=0',
|
||||
this.ppkstr,
|
||||
true
|
||||
]).then(function(boxArtBuffer) {
|
||||
var reader = new FileReader();
|
||||
@ -405,6 +438,7 @@ NvHTTP.prototype = {
|
||||
'/appasset?' + this._buildUidStr() +
|
||||
'&appid=' + appId +
|
||||
'&AssetType=2&AssetIdx=0',
|
||||
this.ppkstr,
|
||||
true
|
||||
]);
|
||||
}
|
||||
@ -423,6 +457,7 @@ NvHTTP.prototype = {
|
||||
'&surroundAudioInfo=' + surroundAudioInfo +
|
||||
'&remoteControllersBitmap=' + gamepadMask +
|
||||
'&gcmap=' + gamepadMask,
|
||||
this.ppkstr,
|
||||
false
|
||||
]);
|
||||
},
|
||||
@ -434,12 +469,13 @@ NvHTTP.prototype = {
|
||||
'&rikey=' + rikey +
|
||||
'&rikeyid=' + rikeyid +
|
||||
'&surroundAudioInfo=' + surroundAudioInfo,
|
||||
this.ppkstr,
|
||||
false
|
||||
]);
|
||||
},
|
||||
|
||||
quitApp: function() {
|
||||
return sendMessage('openUrl', [this._baseUrlHttps + '/cancel?' + this._buildUidStr(), false])
|
||||
return sendMessage('openUrl', [this._baseUrlHttps + '/cancel?' + this._buildUidStr(), this.ppkstr, false])
|
||||
// Refresh server info after quitting because it may silently fail if the
|
||||
// session belongs to a different client.
|
||||
// TODO: We should probably bubble this up to our caller.
|
||||
@ -460,14 +496,12 @@ NvHTTP.prototype = {
|
||||
|
||||
pair: function(randomNumber) {
|
||||
return this.refreshServerInfo().then(function() {
|
||||
if (this.paired)
|
||||
if (this.paired && this.ppkstr)
|
||||
return true;
|
||||
|
||||
if (this.currentGame != 0)
|
||||
return false;
|
||||
|
||||
return sendMessage('pair', [this.serverMajorVersion.toString(), this.address, randomNumber]).then(function(pairStatus) {
|
||||
return sendMessage('openUrl', [this._baseUrlHttps + '/pair?uniqueid=' + this.clientUid + '&devicename=roth&updateState=1&phrase=pairchallenge', false]).then(function(ret) {
|
||||
return sendMessage('pair', [this.serverMajorVersion.toString(), this.address, randomNumber]).then(function(ppkstr) {
|
||||
this.ppkstr = ppkstr;
|
||||
return sendMessage('openUrl', [this._baseUrlHttps + '/pair?uniqueid=' + this.clientUid + '&devicename=roth&updateState=1&phrase=pairchallenge', this.ppkstr, false]).then(function(ret) {
|
||||
$xml = this._parseXML(ret);
|
||||
this.paired = $xml.find('paired').html() == "1";
|
||||
return this.paired;
|
||||
|
Loading…
x
Reference in New Issue
Block a user