Merge with develop
--HG-- branch : compatibility-develop
This commit is contained in:
commit
30512804d5
16 changed files with 707 additions and 11 deletions
35
code/nel/include/nel/gui/curl_certificates.h
Normal file
35
code/nel/include/nel/gui/curl_certificates.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||||
|
// Copyright (C) 2010 Winch Gate Property Limited
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef CL_CURL_CERTIFICATES_HTML_H
|
||||||
|
#define CL_CURL_CERTIFICATES_HTML_H
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
#include "nel/misc/types_nl.h"
|
||||||
|
|
||||||
|
namespace NLGUI
|
||||||
|
{
|
||||||
|
#if defined(NL_OS_WINDOWS)
|
||||||
|
class CCurlCertificates {
|
||||||
|
public:
|
||||||
|
// cURL SSL certificate loading
|
||||||
|
static CURLcode sslCtxFunction(CURL *curl, void *sslctx, void *parm);
|
||||||
|
};
|
||||||
|
#endif // NL_OS_WINDOWS
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
#endif
|
|
@ -264,6 +264,7 @@ namespace NLGUI
|
||||||
// because of multiline, thz parent container will be moved to top
|
// because of multiline, thz parent container will be moved to top
|
||||||
// The good position can be restored by a press on enter then
|
// The good position can be restored by a press on enter then
|
||||||
bool _WantReturn : 1; // Want return char, don't call the enter action handler
|
bool _WantReturn : 1; // Want return char, don't call the enter action handler
|
||||||
|
bool _ClearOnEscape : 1; // clear content when ESC is pressed?
|
||||||
bool _Savable : 1; // should content be saved ?
|
bool _Savable : 1; // should content be saved ?
|
||||||
bool _DefaultInputString : 1; // Is the current input string the default one (should not be edited)
|
bool _DefaultInputString : 1; // Is the current input string the default one (should not be edited)
|
||||||
bool _Frozen : 1; // is the control frozen? (cannot edit in it)
|
bool _Frozen : 1; // is the control frozen? (cannot edit in it)
|
||||||
|
|
|
@ -793,7 +793,7 @@ namespace NLGUI
|
||||||
void doBrowseLocalFile(const std::string &filename);
|
void doBrowseLocalFile(const std::string &filename);
|
||||||
|
|
||||||
// load remote content using either GET or POST
|
// load remote content using either GET or POST
|
||||||
void doBrowseRemoteUrl(const std::string &url, const std::string &referer, bool doPost = false, const SFormFields &formfields = SFormFields());
|
void doBrowseRemoteUrl(std::string url, const std::string &referer, bool doPost = false, const SFormFields &formfields = SFormFields());
|
||||||
|
|
||||||
// render html string as new browser page
|
// render html string as new browser page
|
||||||
bool renderHtmlString(const std::string &html);
|
bool renderHtmlString(const std::string &html);
|
||||||
|
@ -861,7 +861,7 @@ namespace NLGUI
|
||||||
// BnpDownload system
|
// BnpDownload system
|
||||||
void initBnpDownload();
|
void initBnpDownload();
|
||||||
void checkBnpDownload();
|
void checkBnpDownload();
|
||||||
bool addBnpDownload(const std::string &url, const std::string &action, const std::string &script, const std::string &md5sum);
|
bool addBnpDownload(std::string url, const std::string &action, const std::string &script, const std::string &md5sum);
|
||||||
std::string localBnpName(const std::string &url);
|
std::string localBnpName(const std::string &url);
|
||||||
|
|
||||||
void releaseDownloads();
|
void releaseDownloads();
|
||||||
|
|
73
code/nel/include/nel/gui/http_hsts.h
Normal file
73
code/nel/include/nel/gui/http_hsts.h
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||||
|
// Copyright (C) 2010 Winch Gate Property Limited
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef CL_HTTP_HSTS_H
|
||||||
|
#define CL_HTTP_HSTS_H
|
||||||
|
|
||||||
|
#include "nel/misc/types_nl.h"
|
||||||
|
|
||||||
|
namespace NLGUI
|
||||||
|
{
|
||||||
|
// ********************************************************************************
|
||||||
|
struct SHSTSObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SHSTSObject(uint64 expires = 0, bool includeSubDomains = false)
|
||||||
|
: Expires(expires)
|
||||||
|
, IncludeSubDomains(includeSubDomains)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
uint64 Expires;
|
||||||
|
bool IncludeSubDomains;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeping track of HSTS header
|
||||||
|
* \author Meelis Mägi (nimetu)
|
||||||
|
* \date 2017
|
||||||
|
*/
|
||||||
|
class CStrictTransportSecurity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::map<std::string, SHSTSObject> THSTSObject;
|
||||||
|
|
||||||
|
static CStrictTransportSecurity* getInstance();
|
||||||
|
static void release();
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool isSecureHost(const std::string &domain) const;
|
||||||
|
|
||||||
|
// ************************************************************************
|
||||||
|
void init(const std::string& fname);
|
||||||
|
void save();
|
||||||
|
|
||||||
|
void erase(const std::string &domain);
|
||||||
|
void set(const std::string &domain, uint64 expires, bool includeSubDomains);
|
||||||
|
bool get(const std::string &domain, SHSTSObject &hsts) const;
|
||||||
|
void setFromHeader(const std::string &domain, const std::string &header);
|
||||||
|
|
||||||
|
void serial(NLMISC::IStream& f);
|
||||||
|
private:
|
||||||
|
static CStrictTransportSecurity* instance;
|
||||||
|
|
||||||
|
~CStrictTransportSecurity();
|
||||||
|
|
||||||
|
std::string _Filename;
|
||||||
|
THSTSObject _Domains;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
123
code/nel/src/gui/curl_certificates.cpp
Normal file
123
code/nel/src/gui/curl_certificates.cpp
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||||
|
// Copyright (C) 2010 Winch Gate Property Limited
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//#include <crtdbg.h>
|
||||||
|
|
||||||
|
#include "stdpch.h"
|
||||||
|
#include "nel/gui/curl_certificates.h"
|
||||||
|
|
||||||
|
#include <openssl/x509.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
|
#if defined(NL_OS_WINDOWS)
|
||||||
|
#pragma comment(lib, "crypt32.lib")
|
||||||
|
#pragma comment(lib, "cryptui.lib")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace NLMISC;
|
||||||
|
|
||||||
|
#ifdef DEBUG_NEW
|
||||||
|
#define new DEBUG_NEW
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace NLGUI
|
||||||
|
{
|
||||||
|
#if defined(NL_OS_WINDOWS)
|
||||||
|
static std::vector<X509 *> x509CertList;
|
||||||
|
|
||||||
|
//
|
||||||
|
// x509CertList lifetime manager
|
||||||
|
//
|
||||||
|
class SX509Certificates {
|
||||||
|
public:
|
||||||
|
SX509Certificates()
|
||||||
|
{
|
||||||
|
curl_version_info_data *data;
|
||||||
|
data = curl_version_info(CURLVERSION_NOW);
|
||||||
|
if (!(data && data->features & CURL_VERSION_SSPI))
|
||||||
|
{
|
||||||
|
addCertificatesFrom("CA");
|
||||||
|
addCertificatesFrom("AuthRoot");
|
||||||
|
addCertificatesFrom("ROOT");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~SX509Certificates()
|
||||||
|
{
|
||||||
|
for (uint i = 0; i < x509CertList.size(); ++i)
|
||||||
|
{
|
||||||
|
X509_free(x509CertList[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
x509CertList.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void addCertificatesFrom(LPCSTR root)
|
||||||
|
{
|
||||||
|
HCERTSTORE hStore;
|
||||||
|
PCCERT_CONTEXT pContext = NULL;
|
||||||
|
X509 *x509;
|
||||||
|
hStore = CertOpenSystemStore(NULL, root);
|
||||||
|
if (hStore)
|
||||||
|
{
|
||||||
|
while (pContext = CertEnumCertificatesInStore(hStore, pContext))
|
||||||
|
{
|
||||||
|
x509 = NULL;
|
||||||
|
x509 = d2i_X509(NULL, (const unsigned char **)&pContext->pbCertEncoded, pContext->cbCertEncoded);
|
||||||
|
if (x509)
|
||||||
|
{
|
||||||
|
x509CertList.push_back(x509);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CertFreeCertificateContext(pContext);
|
||||||
|
CertCloseStore(hStore, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is called before debug context is set and log ends up in log.log
|
||||||
|
//nlinfo("Loaded %d certificates from '%s' certificate store", List.size(), root);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// this will be initialized on startup and cleared on exit
|
||||||
|
static SX509Certificates x509CertListManager;
|
||||||
|
|
||||||
|
// ***************************************************************************
|
||||||
|
// static
|
||||||
|
CURLcode CCurlCertificates::sslCtxFunction(CURL *curl, void *sslctx, void *parm)
|
||||||
|
{
|
||||||
|
if (x509CertList.size() > 0)
|
||||||
|
{
|
||||||
|
SSL_CTX *ctx = (SSL_CTX*)sslctx;
|
||||||
|
X509_STORE *x509store = SSL_CTX_get_cert_store(ctx);
|
||||||
|
if (x509store)
|
||||||
|
{
|
||||||
|
for (uint i = 0; i < x509CertList.size(); ++i)
|
||||||
|
{
|
||||||
|
X509_STORE_add_cert(x509store, x509CertList[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nlwarning("SSL_CTX_get_cert_store returned NULL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CURLE_OK;
|
||||||
|
}
|
||||||
|
#endif // NL_OS_WINDOWS
|
||||||
|
|
||||||
|
}// namespace
|
||||||
|
|
|
@ -77,6 +77,7 @@ namespace NLGUI
|
||||||
_ResetFocusOnHide(false),
|
_ResetFocusOnHide(false),
|
||||||
_BackupFatherContainerPos(false),
|
_BackupFatherContainerPos(false),
|
||||||
_WantReturn(false),
|
_WantReturn(false),
|
||||||
|
_ClearOnEscape(false),
|
||||||
_Savable(true),
|
_Savable(true),
|
||||||
_DefaultInputString(false),
|
_DefaultInputString(false),
|
||||||
_Frozen(false),
|
_Frozen(false),
|
||||||
|
@ -239,6 +240,11 @@ namespace NLGUI
|
||||||
return toString( _WantReturn );
|
return toString( _WantReturn );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
if( name == "clear_on_escape" )
|
||||||
|
{
|
||||||
|
return toString( _ClearOnEscape );
|
||||||
|
}
|
||||||
|
else
|
||||||
if( name == "savable" )
|
if( name == "savable" )
|
||||||
{
|
{
|
||||||
return toString( _Savable );
|
return toString( _Savable );
|
||||||
|
@ -413,6 +419,14 @@ namespace NLGUI
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
if( name == "clear_on_escape" )
|
||||||
|
{
|
||||||
|
bool b;
|
||||||
|
if( fromString( value, b ) )
|
||||||
|
_ClearOnEscape = b;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
if( name == "savable" )
|
if( name == "savable" )
|
||||||
{
|
{
|
||||||
bool b;
|
bool b;
|
||||||
|
@ -514,6 +528,7 @@ namespace NLGUI
|
||||||
xmlSetProp( node, BAD_CAST "backup_father_container_pos",
|
xmlSetProp( node, BAD_CAST "backup_father_container_pos",
|
||||||
BAD_CAST toString( _BackupFatherContainerPos ).c_str() );
|
BAD_CAST toString( _BackupFatherContainerPos ).c_str() );
|
||||||
xmlSetProp( node, BAD_CAST "want_return", BAD_CAST toString( _WantReturn ).c_str() );
|
xmlSetProp( node, BAD_CAST "want_return", BAD_CAST toString( _WantReturn ).c_str() );
|
||||||
|
xmlSetProp( node, BAD_CAST "clear_on_escape", BAD_CAST toString( _ClearOnEscape ).c_str() );
|
||||||
xmlSetProp( node, BAD_CAST "savable", BAD_CAST toString( _Savable ).c_str() );
|
xmlSetProp( node, BAD_CAST "savable", BAD_CAST toString( _Savable ).c_str() );
|
||||||
xmlSetProp( node, BAD_CAST "max_float_prec", BAD_CAST toString( _MaxFloatPrec ).c_str() );
|
xmlSetProp( node, BAD_CAST "max_float_prec", BAD_CAST toString( _MaxFloatPrec ).c_str() );
|
||||||
|
|
||||||
|
@ -620,6 +635,9 @@ namespace NLGUI
|
||||||
prop = (char*) xmlGetProp( cur, (xmlChar*)"want_return" );
|
prop = (char*) xmlGetProp( cur, (xmlChar*)"want_return" );
|
||||||
if (prop) _WantReturn = convertBool(prop);
|
if (prop) _WantReturn = convertBool(prop);
|
||||||
|
|
||||||
|
prop = (char*) xmlGetProp( cur, (xmlChar*)"clear_on_escape" );
|
||||||
|
if (prop) _ClearOnEscape = convertBool(prop);
|
||||||
|
|
||||||
prop = (char*) xmlGetProp( cur, (xmlChar*)"savable" );
|
prop = (char*) xmlGetProp( cur, (xmlChar*)"savable" );
|
||||||
if (prop) _Savable = convertBool(prop);
|
if (prop) _Savable = convertBool(prop);
|
||||||
|
|
||||||
|
@ -991,6 +1009,11 @@ namespace NLGUI
|
||||||
// stop selection
|
// stop selection
|
||||||
_CurrSelection = NULL;
|
_CurrSelection = NULL;
|
||||||
_CursorAtPreviousLineEnd = false;
|
_CursorAtPreviousLineEnd = false;
|
||||||
|
if (_ClearOnEscape)
|
||||||
|
{
|
||||||
|
setInputString(ucstring(""));
|
||||||
|
triggerOnChangeAH();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case KeyTAB:
|
case KeyTAB:
|
||||||
makeTopWindow();
|
makeTopWindow();
|
||||||
|
|
|
@ -46,6 +46,8 @@
|
||||||
#include "nel/misc/big_file.h"
|
#include "nel/misc/big_file.h"
|
||||||
#include "nel/gui/url_parser.h"
|
#include "nel/gui/url_parser.h"
|
||||||
#include "nel/gui/http_cache.h"
|
#include "nel/gui/http_cache.h"
|
||||||
|
#include "nel/gui/http_hsts.h"
|
||||||
|
#include "nel/gui/curl_certificates.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace NLMISC;
|
using namespace NLMISC;
|
||||||
|
@ -70,6 +72,25 @@ namespace NLGUI
|
||||||
|
|
||||||
CGroupHTML::SWebOptions CGroupHTML::options;
|
CGroupHTML::SWebOptions CGroupHTML::options;
|
||||||
|
|
||||||
|
// Return URL with https is host is in HSTS list
|
||||||
|
static std::string upgradeInsecureUrl(const std::string &url)
|
||||||
|
{
|
||||||
|
if (toLower(url.substr(0, 7)) != "http://") {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
CUrlParser uri(url);
|
||||||
|
if (!CStrictTransportSecurity::getInstance()->isSecureHost(uri.host)){
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef LOG_DL
|
||||||
|
nlwarning("HSTS url : '%s', using https", url.c_str());
|
||||||
|
#endif
|
||||||
|
uri.scheme = "https";
|
||||||
|
|
||||||
|
return uri.toString();
|
||||||
|
}
|
||||||
|
|
||||||
// Active cURL www transfer
|
// Active cURL www transfer
|
||||||
class CCurlWWWData
|
class CCurlWWWData
|
||||||
|
@ -149,6 +170,27 @@ namespace NLGUI
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasHSTSHeader()
|
||||||
|
{
|
||||||
|
// ignore header if not secure connection
|
||||||
|
if (toLower(Url.substr(0, 8)) != "https://")
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return HeadersRecv.count("strict-transport-security") > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string getHSTSHeader()
|
||||||
|
{
|
||||||
|
if (hasHSTSHeader())
|
||||||
|
{
|
||||||
|
return HeadersRecv["strict-transport-security"];
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CURL *Request;
|
CURL *Request;
|
||||||
|
|
||||||
|
@ -356,6 +398,14 @@ namespace NLGUI
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(NL_OS_WINDOWS)
|
||||||
|
// https://
|
||||||
|
if (toLower(download.url.substr(0, 8)) == "https://")
|
||||||
|
{
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, &CCurlCertificates::sslCtxFunction);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
download.data = new CCurlWWWData(curl, download.url);
|
download.data = new CCurlWWWData(curl, download.url);
|
||||||
download.fp = fp;
|
download.fp = fp;
|
||||||
|
|
||||||
|
@ -398,7 +448,7 @@ namespace NLGUI
|
||||||
// Add a image download request in the multi_curl
|
// Add a image download request in the multi_curl
|
||||||
void CGroupHTML::addImageDownload(const string &url, CViewBase *img, const CStyleParams &style, TImageType type)
|
void CGroupHTML::addImageDownload(const string &url, CViewBase *img, const CStyleParams &style, TImageType type)
|
||||||
{
|
{
|
||||||
string finalUrl = getAbsoluteUrl(url);
|
string finalUrl = upgradeInsecureUrl(getAbsoluteUrl(url));
|
||||||
|
|
||||||
// Search if we are not already downloading this url.
|
// Search if we are not already downloading this url.
|
||||||
for(uint i = 0; i < Curls.size(); i++)
|
for(uint i = 0; i < Curls.size(); i++)
|
||||||
|
@ -413,7 +463,7 @@ namespace NLGUI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// use requested url for local name
|
// use requested url for local name (cache)
|
||||||
string dest = localImageName(url);
|
string dest = localImageName(url);
|
||||||
#ifdef LOG_DL
|
#ifdef LOG_DL
|
||||||
nlwarning("add to download '%s' dest '%s' img %p", finalUrl.c_str(), dest.c_str(), img);
|
nlwarning("add to download '%s' dest '%s' img %p", finalUrl.c_str(), dest.c_str(), img);
|
||||||
|
@ -459,8 +509,10 @@ namespace NLGUI
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a bnp download request in the multi_curl, return true if already downloaded
|
// Add a bnp download request in the multi_curl, return true if already downloaded
|
||||||
bool CGroupHTML::addBnpDownload(const string &url, const string &action, const string &script, const string &md5sum)
|
bool CGroupHTML::addBnpDownload(string url, const string &action, const string &script, const string &md5sum)
|
||||||
{
|
{
|
||||||
|
url = upgradeInsecureUrl(getAbsoluteUrl(url));
|
||||||
|
|
||||||
// Search if we are not already downloading this url.
|
// Search if we are not already downloading this url.
|
||||||
for(uint i = 0; i < Curls.size(); i++)
|
for(uint i = 0; i < Curls.size(); i++)
|
||||||
{
|
{
|
||||||
|
@ -569,6 +621,12 @@ namespace NLGUI
|
||||||
#ifdef LOG_DL
|
#ifdef LOG_DL
|
||||||
nlwarning("(%s) web transfer '%p' completed with status %d, http %d, url (len %d) '%s'", _Id.c_str(), _CurlWWW->Request, res, code, _CurlWWW->Url.size(), _CurlWWW->Url.c_str());
|
nlwarning("(%s) web transfer '%p' completed with status %d, http %d, url (len %d) '%s'", _Id.c_str(), _CurlWWW->Request, res, code, _CurlWWW->Url.size(), _CurlWWW->Url.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
// save HSTS header from all requests regardless of HTTP code
|
||||||
|
if (res == CURLE_OK && _CurlWWW->hasHSTSHeader())
|
||||||
|
{
|
||||||
|
CUrlParser uri(_CurlWWW->Url);
|
||||||
|
CStrictTransportSecurity::getInstance()->setFromHeader(uri.host, _CurlWWW->getHSTSHeader());
|
||||||
|
}
|
||||||
|
|
||||||
if (res != CURLE_OK)
|
if (res != CURLE_OK)
|
||||||
{
|
{
|
||||||
|
@ -655,6 +713,12 @@ namespace NLGUI
|
||||||
#endif
|
#endif
|
||||||
curl_multi_remove_handle(MultiCurl, it->data->Request);
|
curl_multi_remove_handle(MultiCurl, it->data->Request);
|
||||||
|
|
||||||
|
// save HSTS header from all requests regardless of HTTP code
|
||||||
|
if (res == CURLE_OK && it->data->hasHSTSHeader())
|
||||||
|
{
|
||||||
|
CStrictTransportSecurity::getInstance()->setFromHeader(uri.host, it->data->getHSTSHeader());
|
||||||
|
}
|
||||||
|
|
||||||
string tmpfile = it->dest + ".tmp";
|
string tmpfile = it->dest + ".tmp";
|
||||||
if(res != CURLE_OK || r < 200 || r >= 300 || (!it->md5sum.empty() && (it->md5sum != getMD5(tmpfile).toString())))
|
if(res != CURLE_OK || r < 200 || r >= 300 || (!it->md5sum.empty() && (it->md5sum != getMD5(tmpfile).toString())))
|
||||||
{
|
{
|
||||||
|
@ -5231,7 +5295,7 @@ namespace NLGUI
|
||||||
}
|
}
|
||||||
|
|
||||||
// ***************************************************************************
|
// ***************************************************************************
|
||||||
void CGroupHTML::doBrowseRemoteUrl(const std::string &url, const std::string &referer, bool doPost, const SFormFields &formfields)
|
void CGroupHTML::doBrowseRemoteUrl(std::string url, const std::string &referer, bool doPost, const SFormFields &formfields)
|
||||||
{
|
{
|
||||||
// Stop previous request and remove content
|
// Stop previous request and remove content
|
||||||
stopBrowse ();
|
stopBrowse ();
|
||||||
|
@ -5245,6 +5309,8 @@ namespace NLGUI
|
||||||
else
|
else
|
||||||
setTitle (_TitlePrefix + " - " + CI18N::get("uiPleaseWait"));
|
setTitle (_TitlePrefix + " - " + CI18N::get("uiPleaseWait"));
|
||||||
|
|
||||||
|
url = upgradeInsecureUrl(url);
|
||||||
|
|
||||||
#if LOG_DL
|
#if LOG_DL
|
||||||
nlwarning("(%s) browse url (trusted=%s) '%s', referer='%s', post='%s', nb form values %d",
|
nlwarning("(%s) browse url (trusted=%s) '%s', referer='%s', post='%s', nb form values %d",
|
||||||
_Id.c_str(), (_TrustedDomain ? "true" :"false"), url.c_str(), referer.c_str(), (doPost ? "true" : "false"), formfields.Values.size());
|
_Id.c_str(), (_TrustedDomain ? "true" :"false"), url.c_str(), referer.c_str(), (doPost ? "true" : "false"), formfields.Values.size());
|
||||||
|
@ -5264,6 +5330,14 @@ namespace NLGUI
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(NL_OS_WINDOWS)
|
||||||
|
// https://
|
||||||
|
if (toLower(url.substr(0, 8)) == "https://")
|
||||||
|
{
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, &CCurlCertificates::sslCtxFunction);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// do not follow redirects, we have own handler
|
// do not follow redirects, we have own handler
|
||||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 0);
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 0);
|
||||||
// after redirect
|
// after redirect
|
||||||
|
|
245
code/nel/src/gui/http_hsts.cpp
Normal file
245
code/nel/src/gui/http_hsts.cpp
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
||||||
|
// Copyright (C) 2010 Winch Gate Property Limited
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as
|
||||||
|
// published by the Free Software Foundation, either version 3 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "stdpch.h"
|
||||||
|
#include "nel/gui/http_hsts.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace NLMISC;
|
||||||
|
|
||||||
|
#ifdef DEBUG_NEW
|
||||||
|
#define new DEBUG_NEW
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace NLGUI {
|
||||||
|
CStrictTransportSecurity* CStrictTransportSecurity::instance = NULL;
|
||||||
|
CStrictTransportSecurity* CStrictTransportSecurity::getInstance()
|
||||||
|
{
|
||||||
|
if (!instance)
|
||||||
|
{
|
||||||
|
instance= new CStrictTransportSecurity();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStrictTransportSecurity::release()
|
||||||
|
{
|
||||||
|
delete instance;
|
||||||
|
instance = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
CStrictTransportSecurity::~CStrictTransportSecurity()
|
||||||
|
{
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************************************************************************
|
||||||
|
bool CStrictTransportSecurity::isSecureHost(const std::string &domain) const
|
||||||
|
{
|
||||||
|
SHSTSObject hsts;
|
||||||
|
if (get(domain, hsts))
|
||||||
|
{
|
||||||
|
time_t currentTime;
|
||||||
|
time(¤tTime);
|
||||||
|
|
||||||
|
return (hsts.Expires < currentTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ************************************************************************
|
||||||
|
void CStrictTransportSecurity::erase(const std::string &domain)
|
||||||
|
{
|
||||||
|
if (_Domains.count(domain) > 0)
|
||||||
|
{
|
||||||
|
_Domains.erase(domain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStrictTransportSecurity::set(const std::string &domain, uint64 expires, bool includeSubDomains)
|
||||||
|
{
|
||||||
|
if (expires == 0)
|
||||||
|
{
|
||||||
|
erase(domain);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_Domains[domain].Expires = expires;
|
||||||
|
_Domains[domain].IncludeSubDomains = includeSubDomains;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CStrictTransportSecurity::get(const std::string &domain, SHSTSObject &hsts) const
|
||||||
|
{
|
||||||
|
if (domain.empty() || _Domains.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (_Domains.count(domain) > 0)
|
||||||
|
{
|
||||||
|
hsts = _Domains.at(domain);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t firstOf = domain.find_first_of(".");
|
||||||
|
size_t lastOf = domain.find_last_of(".");
|
||||||
|
while(firstOf != lastOf)
|
||||||
|
{
|
||||||
|
std::string tmp;
|
||||||
|
tmp = domain.substr(firstOf+1);
|
||||||
|
if (_Domains.count(tmp))
|
||||||
|
{
|
||||||
|
if (_Domains.at(tmp).IncludeSubDomains)
|
||||||
|
{
|
||||||
|
hsts = _Domains.at(tmp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
firstOf = domain.find_first_of(".", firstOf + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStrictTransportSecurity::init(const std::string &fname)
|
||||||
|
{
|
||||||
|
_Domains.clear();
|
||||||
|
_Filename = fname;
|
||||||
|
|
||||||
|
if (_Filename.empty() || !CFile::fileExists(_Filename))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CIFile in;
|
||||||
|
if (!in.open(_Filename))
|
||||||
|
{
|
||||||
|
nlwarning("Unable to open %s for reading", _Filename.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
serial(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStrictTransportSecurity::save()
|
||||||
|
{
|
||||||
|
if (_Filename.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_Domains.empty())
|
||||||
|
{
|
||||||
|
CFile::deleteFile(_Filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
COFile out;
|
||||||
|
if (!out.open(_Filename))
|
||||||
|
{
|
||||||
|
nlwarning("Unable to open %s for writing", _Filename.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
serial(out);
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStrictTransportSecurity::serial(NLMISC::IStream& f)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
f.serialVersion(1);
|
||||||
|
// HSTS
|
||||||
|
f.serialCheck(NELID("STSH"));
|
||||||
|
|
||||||
|
if (f.isReading())
|
||||||
|
{
|
||||||
|
uint32 nbItems;
|
||||||
|
f.serial(nbItems);
|
||||||
|
for(uint32 k = 0; k < nbItems; ++k)
|
||||||
|
{
|
||||||
|
std::string domain;
|
||||||
|
f.serial(domain);
|
||||||
|
f.serial(_Domains[domain].Expires);
|
||||||
|
f.serial(_Domains[domain].IncludeSubDomains);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32 nbItems = _Domains.size();
|
||||||
|
f.serial(nbItems);
|
||||||
|
for (THSTSObject::iterator it = _Domains.begin(); it != _Domains.end(); ++it)
|
||||||
|
{
|
||||||
|
std::string domain(it->first);
|
||||||
|
f.serial(domain);
|
||||||
|
f.serial(_Domains[domain].Expires);
|
||||||
|
f.serial(_Domains[domain].IncludeSubDomains);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
_Domains.clear();
|
||||||
|
nlwarning("Invalid HTST file format (%s)", _Filename.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ***************************************************************************
|
||||||
|
void CStrictTransportSecurity::setFromHeader(const std::string &domain, const std::string &header)
|
||||||
|
{
|
||||||
|
// max-age=<seconds>; includeSubdomains; preload;
|
||||||
|
std::vector<std::string> elements;
|
||||||
|
NLMISC::splitString(toLower(header), ";", elements);
|
||||||
|
if (elements.empty()) return;
|
||||||
|
|
||||||
|
time_t currentTime;
|
||||||
|
time(¤tTime);
|
||||||
|
|
||||||
|
uint64 expire = 0;
|
||||||
|
bool includeSubDomains = false;
|
||||||
|
|
||||||
|
for(uint i=0; i< elements.size(); ++i)
|
||||||
|
{
|
||||||
|
std::string str(trim(elements[i]));
|
||||||
|
if (str.substr(0, 8) == "max-age=")
|
||||||
|
{
|
||||||
|
uint64 ttl;
|
||||||
|
if (fromString(str.substr(8), ttl))
|
||||||
|
{
|
||||||
|
if (ttl > 0)
|
||||||
|
{
|
||||||
|
expire = currentTime + ttl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (str == "includesubdomains")
|
||||||
|
{
|
||||||
|
includeSubDomains = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expire == 0)
|
||||||
|
{
|
||||||
|
erase(domain);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
set(domain, expire, includeSubDomains);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -549,7 +549,7 @@
|
||||||
pop_min_h="240"
|
pop_min_h="240"
|
||||||
pop_max_w="920"
|
pop_max_w="920"
|
||||||
pop_max_h="1600"
|
pop_max_h="1600"
|
||||||
w="300"
|
w="400"
|
||||||
h="400"
|
h="400"
|
||||||
movable="true"
|
movable="true"
|
||||||
active="false"
|
active="false"
|
||||||
|
|
|
@ -2655,6 +2655,7 @@
|
||||||
fontsize="10"
|
fontsize="10"
|
||||||
backup_father_container_pos="false"
|
backup_father_container_pos="false"
|
||||||
want_return="false"
|
want_return="false"
|
||||||
|
clear_on_escape="false"
|
||||||
color="255 255 255 255"
|
color="255 255 255 255"
|
||||||
continuous_text_update="false"
|
continuous_text_update="false"
|
||||||
bg_texture="W_box_blank.tga"
|
bg_texture="W_box_blank.tga"
|
||||||
|
@ -2695,6 +2696,7 @@
|
||||||
menu_r="#menu_r"
|
menu_r="#menu_r"
|
||||||
max_historic="#max_historic"
|
max_historic="#max_historic"
|
||||||
want_return="#want_return"
|
want_return="#want_return"
|
||||||
|
clear_on_escape="#clear_on_escape"
|
||||||
backup_father_container_pos="#backup_father_container_pos"
|
backup_father_container_pos="#backup_father_container_pos"
|
||||||
on_focus_lost="#on_focus_lost"
|
on_focus_lost="#on_focus_lost"
|
||||||
on_focus_lost_params="#on_focus_lost_params"
|
on_focus_lost_params="#on_focus_lost_params"
|
||||||
|
@ -6587,6 +6589,18 @@
|
||||||
dblink="UI:SAVE:#inv_type:FILTER_ARMOR"
|
dblink="UI:SAVE:#inv_type:FILTER_ARMOR"
|
||||||
texture="filter_armor.tga"
|
texture="filter_armor.tga"
|
||||||
tooltip="uittFilterArmor" />
|
tooltip="uittFilterArmor" />
|
||||||
|
<instance template="edit_box_widget"
|
||||||
|
id="inv_query_eb"
|
||||||
|
posref="BR BR"
|
||||||
|
x="-190"
|
||||||
|
y="1"
|
||||||
|
w="100"
|
||||||
|
clear_on_escape="true"
|
||||||
|
enter_recover_focus="false"
|
||||||
|
max_num_chars="20"
|
||||||
|
max_historic="0"
|
||||||
|
onenter="inv_set_search"
|
||||||
|
onchange="inv_set_search" onchange_params="#inv_type" />
|
||||||
<!-- details -->
|
<!-- details -->
|
||||||
<instance template="tinv_item_list_icon_swap"
|
<instance template="tinv_item_list_icon_swap"
|
||||||
id="detail"
|
id="detail"
|
||||||
|
|
|
@ -69,6 +69,7 @@
|
||||||
#include "interface_v3/sbrick_manager.h"
|
#include "interface_v3/sbrick_manager.h"
|
||||||
#include "nel/gui/widget_manager.h"
|
#include "nel/gui/widget_manager.h"
|
||||||
#include "nel/gui/http_cache.h"
|
#include "nel/gui/http_cache.h"
|
||||||
|
#include "nel/gui/http_hsts.h"
|
||||||
//
|
//
|
||||||
#include "gabarit.h"
|
#include "gabarit.h"
|
||||||
#include "hair_set.h"
|
#include "hair_set.h"
|
||||||
|
@ -1370,6 +1371,8 @@ void prelogInit()
|
||||||
CHttpCache::getInstance()->setCacheIndex("cache/cache.index");
|
CHttpCache::getInstance()->setCacheIndex("cache/cache.index");
|
||||||
CHttpCache::getInstance()->init();
|
CHttpCache::getInstance()->init();
|
||||||
|
|
||||||
|
CStrictTransportSecurity::getInstance()->init("save/hsts-list.save");
|
||||||
|
|
||||||
// Register the reflected classes
|
// Register the reflected classes
|
||||||
registerInterfaceElements();
|
registerInterfaceElements();
|
||||||
|
|
||||||
|
|
|
@ -2960,6 +2960,8 @@ void CDBCtrlSheet::swapSheet(CDBCtrlSheet *other)
|
||||||
swapDBProps(getItemRMClassTypePtr(), other->getItemRMClassTypePtr());
|
swapDBProps(getItemRMClassTypePtr(), other->getItemRMClassTypePtr());
|
||||||
swapDBProps(getItemRMFaberStatTypePtr(), other->getItemRMFaberStatTypePtr());
|
swapDBProps(getItemRMFaberStatTypePtr(), other->getItemRMFaberStatTypePtr());
|
||||||
swapDBProps(getItemPrerequisitValidPtr(), other->getItemPrerequisitValidPtr());
|
swapDBProps(getItemPrerequisitValidPtr(), other->getItemPrerequisitValidPtr());
|
||||||
|
swapDBProps(getItemSerialPtr(), other->getItemSerialPtr());
|
||||||
|
swapDBProps(getItemCreateTimePtr(), other->getItemCreateTimePtr());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3539,6 +3541,10 @@ void CDBCtrlSheet::copyAspect(CDBCtrlSheet *dest)
|
||||||
dest->setItemRMFaberStatType(getItemRMFaberStatType());
|
dest->setItemRMFaberStatType(getItemRMFaberStatType());
|
||||||
// copy prerequisit valid flag
|
// copy prerequisit valid flag
|
||||||
dest->setItemPrerequisitValid(getItemPrerequisitValid());
|
dest->setItemPrerequisitValid(getItemPrerequisitValid());
|
||||||
|
// copy item serial
|
||||||
|
dest->setItemSerial(getItemSerial());
|
||||||
|
// copy item create time
|
||||||
|
dest->setItemCreateTime(getItemCreateTime());
|
||||||
}
|
}
|
||||||
// if brick, sphrase or sphraseId
|
// if brick, sphrase or sphraseId
|
||||||
if(isSBrick() || isSPhrase() || isSPhraseId())
|
if(isSBrick() || isSPhrase() || isSPhraseId())
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
|
|
||||||
// For handlers
|
// For handlers
|
||||||
#include "nel/gui/action_handler.h"
|
#include "nel/gui/action_handler.h"
|
||||||
|
#include "nel/gui/group_editbox.h"
|
||||||
#include "dbctrl_sheet.h"
|
#include "dbctrl_sheet.h"
|
||||||
|
|
||||||
#include "../sheet_manager.h"
|
#include "../sheet_manager.h"
|
||||||
|
@ -2010,6 +2011,18 @@ bool SBagOptions::parse(xmlNodePtr cur, CInterfaceGroup * /* parentGroup */)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ***************************************************************************
|
||||||
|
void SBagOptions::setSearchFilter(const ucstring &s)
|
||||||
|
{
|
||||||
|
SearchFilter.clear();
|
||||||
|
SearchFilterChanged = true;
|
||||||
|
|
||||||
|
if (!s.empty())
|
||||||
|
{
|
||||||
|
splitUCString(toLower(s), ucstring(" "), SearchFilter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ***************************************************************************
|
// ***************************************************************************
|
||||||
bool SBagOptions::isSomethingChanged()
|
bool SBagOptions::isSomethingChanged()
|
||||||
{
|
{
|
||||||
|
@ -2057,6 +2070,12 @@ bool SBagOptions::isSomethingChanged()
|
||||||
LastDbFilterTP = (DbFilterTP->getValue8() != 0);
|
LastDbFilterTP = (DbFilterTP->getValue8() != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SearchFilterChanged)
|
||||||
|
{
|
||||||
|
bRet = true;
|
||||||
|
SearchFilterChanged = false;
|
||||||
|
}
|
||||||
|
|
||||||
return bRet;
|
return bRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2075,6 +2094,26 @@ bool SBagOptions::canDisplay(CDBCtrlSheet *pCS) const
|
||||||
const CItemSheet *pIS = pCS->asItemSheet();
|
const CItemSheet *pIS = pCS->asItemSheet();
|
||||||
if (pIS != NULL)
|
if (pIS != NULL)
|
||||||
{
|
{
|
||||||
|
if (SearchFilter.size() > 0)
|
||||||
|
{
|
||||||
|
bool match = true;
|
||||||
|
ucstring lcName = toLower(pCS->getItemActualName());
|
||||||
|
|
||||||
|
// add item quality as a keyword to match
|
||||||
|
if (pCS->getQuality() > 1)
|
||||||
|
{
|
||||||
|
lcName += ucstring(" " + toString(pCS->getQuality()));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint i = 0; i< SearchFilter.size(); ++i)
|
||||||
|
{
|
||||||
|
if (lcName.find(SearchFilter[i]) == ucstring::npos)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Armor
|
// Armor
|
||||||
if ((pIS->Family == ITEMFAMILY::ARMOR) ||
|
if ((pIS->Family == ITEMFAMILY::ARMOR) ||
|
||||||
(pIS->Family == ITEMFAMILY::JEWELRY))
|
(pIS->Family == ITEMFAMILY::JEWELRY))
|
||||||
|
@ -2455,6 +2494,30 @@ class CHandlerInvDrag : public IActionHandler
|
||||||
};
|
};
|
||||||
REGISTER_ACTION_HANDLER( CHandlerInvDrag, "inv_drag" );
|
REGISTER_ACTION_HANDLER( CHandlerInvDrag, "inv_drag" );
|
||||||
|
|
||||||
|
// **********************************************************************************************************
|
||||||
|
class CHandlerInvSetSearch : public IActionHandler
|
||||||
|
{
|
||||||
|
void execute (CCtrlBase *pCaller, const std::string &sParams)
|
||||||
|
{
|
||||||
|
if (!pCaller) return;
|
||||||
|
|
||||||
|
CGroupEditBox *eb = dynamic_cast<CGroupEditBox *>(pCaller);
|
||||||
|
if (!eb) return;
|
||||||
|
|
||||||
|
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
||||||
|
|
||||||
|
// ui:interface:inventory:content:bag:iil:inv_query_eb:eb
|
||||||
|
string invId = pCaller->getParent()->getParent()->getId();
|
||||||
|
|
||||||
|
CDBGroupListSheetBag *pList = dynamic_cast<CDBGroupListSheetBag*>(CWidgetManager::getInstance()->getElementFromId(invId + ":bag_list"));
|
||||||
|
if (pList != NULL) pList->setSearchFilter(eb->getInputString());
|
||||||
|
|
||||||
|
CDBGroupIconListBag *pIcons = dynamic_cast<CDBGroupIconListBag*>(CWidgetManager::getInstance()->getElementFromId(invId + ":bag_icons"));
|
||||||
|
if (pIcons != NULL) pIcons->setSearchFilter(eb->getInputString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
REGISTER_ACTION_HANDLER( CHandlerInvSetSearch, "inv_set_search" );
|
||||||
|
|
||||||
// ***************************************************************************
|
// ***************************************************************************
|
||||||
// COMMON INVENTORIES Test if we can drop an item to a slot or a list
|
// COMMON INVENTORIES Test if we can drop an item to a slot or a list
|
||||||
class CHandlerInvCanDropTo : public IActionHandler
|
class CHandlerInvCanDropTo : public IActionHandler
|
||||||
|
|
|
@ -519,18 +519,26 @@ struct SBagOptions
|
||||||
bool LastDbFilterMP;
|
bool LastDbFilterMP;
|
||||||
bool LastDbFilterMissMP;
|
bool LastDbFilterMissMP;
|
||||||
bool LastDbFilterTP;
|
bool LastDbFilterTP;
|
||||||
|
|
||||||
|
bool SearchFilterChanged;
|
||||||
|
std::vector<ucstring> SearchFilter;
|
||||||
|
|
||||||
// -----------------------
|
// -----------------------
|
||||||
SBagOptions()
|
SBagOptions()
|
||||||
{
|
{
|
||||||
InvType = CInventoryManager::InvUnknown;
|
InvType = CInventoryManager::InvUnknown;
|
||||||
DbFilterArmor = DbFilterWeapon = DbFilterTool = DbFilterMP = DbFilterMissMP = DbFilterTP = NULL;
|
DbFilterArmor = DbFilterWeapon = DbFilterTool = DbFilterMP = DbFilterMissMP = DbFilterTP = NULL;
|
||||||
LastDbFilterArmor = LastDbFilterWeapon = LastDbFilterTool = LastDbFilterMP = LastDbFilterMissMP = LastDbFilterTP = false;
|
LastDbFilterArmor = LastDbFilterWeapon = LastDbFilterTool = LastDbFilterMP = LastDbFilterMissMP = LastDbFilterTP = false;
|
||||||
|
SearchFilterChanged = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse (xmlNodePtr cur, CInterfaceGroup *parentGroup);
|
bool parse (xmlNodePtr cur, CInterfaceGroup *parentGroup);
|
||||||
|
|
||||||
bool isSomethingChanged(); // From last call ?
|
bool isSomethingChanged(); // From last call ?
|
||||||
|
|
||||||
|
bool isSearchFilterChanged() const { return SearchFilterChanged; }
|
||||||
|
void setSearchFilter(const ucstring &s);
|
||||||
|
|
||||||
bool getFilterArmor() const
|
bool getFilterArmor() const
|
||||||
{
|
{
|
||||||
if (DbFilterArmor == NULL) return true;
|
if (DbFilterArmor == NULL) return true;
|
||||||
|
@ -621,6 +629,8 @@ public:
|
||||||
// Return true if the sheet can be displayed due to filters
|
// Return true if the sheet can be displayed due to filters
|
||||||
bool canDisplay(CDBCtrlSheet *pCS) { return _BO.canDisplay(pCS); }
|
bool canDisplay(CDBCtrlSheet *pCS) { return _BO.canDisplay(pCS); }
|
||||||
|
|
||||||
|
void setSearchFilter(const ucstring &s) { _BO.setSearchFilter(s); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
SBagOptions _BO;
|
SBagOptions _BO;
|
||||||
|
@ -652,6 +662,8 @@ public:
|
||||||
// Return true if the sheet can be displayed due to filters
|
// Return true if the sheet can be displayed due to filters
|
||||||
bool canDisplay(CDBCtrlSheet *pCS) const { return _BO.canDisplay(pCS); }
|
bool canDisplay(CDBCtrlSheet *pCS) const { return _BO.canDisplay(pCS); }
|
||||||
|
|
||||||
|
void setSearchFilter(const ucstring &s) { _BO.setSearchFilter(s); }
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// A child node
|
// A child node
|
||||||
|
|
|
@ -73,14 +73,29 @@ bool CItemGroup::contains(CDBCtrlSheet *other, SLOT_EQUIPMENT::TSlotEquipment &s
|
||||||
|
|
||||||
void CItemGroup::addItem(sint32 createTime, sint32 serial, SLOT_EQUIPMENT::TSlotEquipment slot)
|
void CItemGroup::addItem(sint32 createTime, sint32 serial, SLOT_EQUIPMENT::TSlotEquipment slot)
|
||||||
{
|
{
|
||||||
|
//Don't add an item if it already exists, this could cause issue
|
||||||
|
// It's happening either if we are creating a group with a 2 hands items (and the item is found both in handR and handL)
|
||||||
|
// Or if an user incorrectly edit his group file
|
||||||
|
for(int i=0; i<Items.size(); i++)
|
||||||
|
{
|
||||||
|
if( Items[i].createTime == createTime && Items[i].serial == serial)
|
||||||
|
{
|
||||||
|
nldebug("Not adding duplicate item, createTime: %d, serial: %d", createTime, serial);
|
||||||
|
//In this case, we are adding the duplicate item for a 2 hands item
|
||||||
|
//If it's saved as a left hand item, save it as a right hand item instead (so we have only 1 correct item)
|
||||||
|
if(Items[i].slot == SLOT_EQUIPMENT::TSlotEquipment::HANDL && slot == SLOT_EQUIPMENT::TSlotEquipment::HANDR)
|
||||||
|
Items[i].slot = SLOT_EQUIPMENT::TSlotEquipment::HANDR;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
Items.push_back(CItem(createTime, serial, slot));
|
Items.push_back(CItem(createTime, serial, slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CItemGroup::addRemove(std::string slotName)
|
void CItemGroup::addRemove(std::string slotName)
|
||||||
{
|
{
|
||||||
SLOT_EQUIPMENT::TSlotEquipment slot = SLOT_EQUIPMENT::stringToSlotEquipment(NLMISC::toUpper(slotName));
|
SLOT_EQUIPMENT::TSlotEquipment slot = SLOT_EQUIPMENT::stringToSlotEquipment(NLMISC::toUpper(slotName));
|
||||||
if(slot)
|
if(slot != SLOT_EQUIPMENT::UNDEFINED)
|
||||||
removeBeforeEquip.push_back(slot);
|
addRemove(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CItemGroup::addRemove(SLOT_EQUIPMENT::TSlotEquipment slot)
|
void CItemGroup::addRemove(SLOT_EQUIPMENT::TSlotEquipment slot)
|
||||||
|
@ -158,9 +173,16 @@ void CItemGroup::readFrom(xmlNodePtr node)
|
||||||
ptrName = (char*) xmlGetProp(curNode, (xmlChar*)"maxPrice");
|
ptrName = (char*) xmlGetProp(curNode, (xmlChar*)"maxPrice");
|
||||||
if (ptrName) NLMISC::fromString((const char*)ptrName, item.maxPrice);
|
if (ptrName) NLMISC::fromString((const char*)ptrName, item.maxPrice);
|
||||||
item.usePrice = (item.minPrice != 0 || item.maxPrice != std::numeric_limits<uint32>::max());
|
item.usePrice = (item.minPrice != 0 || item.maxPrice != std::numeric_limits<uint32>::max());
|
||||||
|
if(item.createTime != 0)
|
||||||
|
{
|
||||||
|
addItem(item.createTime, item.serial, item.slot);
|
||||||
|
}
|
||||||
|
// Old load : keep for compatibility / migration reasons
|
||||||
|
else
|
||||||
|
{
|
||||||
Items.push_back(item);
|
Items.push_back(item);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (strcmp((char*)curNode->name, "remove") == 0)
|
if (strcmp((char*)curNode->name, "remove") == 0)
|
||||||
{
|
{
|
||||||
std::string slot;
|
std::string slot;
|
||||||
|
|
|
@ -95,6 +95,7 @@
|
||||||
#include "nel/gui/lua_manager.h"
|
#include "nel/gui/lua_manager.h"
|
||||||
#include "item_group_manager.h"
|
#include "item_group_manager.h"
|
||||||
#include "nel/gui/http_cache.h"
|
#include "nel/gui/http_cache.h"
|
||||||
|
#include "nel/gui/http_hsts.h"
|
||||||
|
|
||||||
///////////
|
///////////
|
||||||
// USING //
|
// USING //
|
||||||
|
@ -688,6 +689,7 @@ void release()
|
||||||
CViewRenderer::release();
|
CViewRenderer::release();
|
||||||
CIXml::releaseLibXml();
|
CIXml::releaseLibXml();
|
||||||
CHttpCache::release();
|
CHttpCache::release();
|
||||||
|
CStrictTransportSecurity::release();
|
||||||
|
|
||||||
#if FINAL_VERSION
|
#if FINAL_VERSION
|
||||||
// openURL ("http://ryzom.com/exit/");
|
// openURL ("http://ryzom.com/exit/");
|
||||||
|
|
Loading…
Reference in a new issue