Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / gui / http_hsts.cpp
blob2befe7932bc7aad795be95adb64155bf423bdb28
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2017 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2018-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stdpch.h"
21 #include "nel/gui/http_hsts.h"
23 using namespace std;
24 using namespace NLMISC;
26 #ifdef DEBUG_NEW
27 #define new DEBUG_NEW
28 #endif
30 namespace NLGUI {
31 CStrictTransportSecurity* CStrictTransportSecurity::instance = NULL;
32 CStrictTransportSecurity* CStrictTransportSecurity::getInstance()
34 if (!instance)
36 instance= new CStrictTransportSecurity();
38 return instance;
41 void CStrictTransportSecurity::release()
43 delete instance;
44 instance = NULL;
47 CStrictTransportSecurity::~CStrictTransportSecurity()
49 save();
52 // ************************************************************************
53 bool CStrictTransportSecurity::isSecureHost(const std::string &domain) const
55 SHSTSObject hsts;
56 if (get(domain, hsts))
58 time_t currentTime;
59 time(&currentTime);
61 return (hsts.Expires > currentTime);
64 return false;
67 // ************************************************************************
68 void CStrictTransportSecurity::erase(const std::string &domain)
70 if (_Domains.count(domain) > 0)
72 _Domains.erase(domain);
76 void CStrictTransportSecurity::set(const std::string &domain, uint64 expires, bool includeSubDomains)
78 if (expires == 0)
80 erase(domain);
81 return;
84 _Domains[domain].Expires = expires;
85 _Domains[domain].IncludeSubDomains = includeSubDomains;
88 bool CStrictTransportSecurity::get(const std::string &domain, SHSTSObject &hsts) const
90 if (domain.empty() || _Domains.empty())
91 return false;
93 THSTSObjectMap::const_iterator itHsts;
95 itHsts = _Domains.find(domain);
96 if (itHsts != _Domains.end())
98 hsts = itHsts->second;
99 return true;
102 size_t firstOf = domain.find_first_of(".");
103 size_t lastOf = domain.find_last_of(".");
104 while(firstOf != lastOf)
106 std::string tmp;
107 tmp = domain.substr(firstOf+1);
108 itHsts = _Domains.find(tmp);
109 if (itHsts != _Domains.end())
111 if (itHsts->second.IncludeSubDomains)
113 hsts = itHsts->second;
114 return true;
117 return false;
120 firstOf = domain.find_first_of(".", firstOf + 1);
123 return false;
126 void CStrictTransportSecurity::init(const std::string &fname)
128 _Domains.clear();
129 _Filename = fname;
131 if (_Filename.empty() || !CFile::fileExists(_Filename))
133 return;
136 CIFile in;
137 if (!in.open(_Filename))
139 nlwarning("Unable to open %s for reading", _Filename.c_str());
140 return;
143 serial(in);
146 void CStrictTransportSecurity::save()
148 if (_Filename.empty())
149 return;
151 if (_Domains.empty())
153 CFile::deleteFile(_Filename);
154 return;
157 COFile out;
158 if (!out.open(_Filename))
160 nlwarning("Unable to open %s for writing", _Filename.c_str());
161 return;
164 serial(out);
165 out.close();
168 void CStrictTransportSecurity::serial(NLMISC::IStream& f)
172 f.serialVersion(1);
173 // HSTS
174 f.serialCheck(NELID("STSH"));
176 if (f.isReading())
178 uint32 nbItems;
179 f.serial(nbItems);
180 for(uint32 k = 0; k < nbItems; ++k)
182 std::string domain;
183 f.serial(domain);
184 f.serial(_Domains[domain].Expires);
185 f.serial(_Domains[domain].IncludeSubDomains);
188 else
190 uint32 nbItems = _Domains.size();
191 f.serial(nbItems);
192 for (THSTSObjectMap::iterator it = _Domains.begin(); it != _Domains.end(); ++it)
194 std::string domain(it->first);
195 f.serial(domain);
196 f.serial(_Domains[domain].Expires);
197 f.serial(_Domains[domain].IncludeSubDomains);
201 catch (...)
203 _Domains.clear();
204 nlwarning("Invalid HTST file format (%s)", _Filename.c_str());
208 // ***************************************************************************
209 void CStrictTransportSecurity::setFromHeader(const std::string &domain, const std::string &header)
211 // max-age=<seconds>; includeSubdomains; preload;
212 std::vector<std::string> elements;
213 NLMISC::splitString(toLowerAscii(header), ";", elements);
214 if (elements.empty()) return;
216 time_t currentTime;
217 time(&currentTime);
219 uint64 expire = 0;
220 bool includeSubDomains = false;
222 for(uint i=0; i< elements.size(); ++i)
224 std::string str(trim(elements[i]));
225 if (str.substr(0, 8) == "max-age=")
227 uint64 ttl;
228 if (fromString(str.substr(8), ttl))
230 if (ttl > 0)
232 expire = currentTime + ttl;
236 else if (str == "includesubdomains")
238 includeSubDomains = true;
242 if (expire == 0)
244 erase(domain);
246 else
248 set(domain, expire, includeSubDomains);