|
|
@ -46,6 +46,7 @@ |
|
|
|
#include "base/http/httperror.h" |
|
|
|
#include "base/http/httperror.h" |
|
|
|
#include "base/logger.h" |
|
|
|
#include "base/logger.h" |
|
|
|
#include "base/preferences.h" |
|
|
|
#include "base/preferences.h" |
|
|
|
|
|
|
|
#include "base/types.h" |
|
|
|
#include "base/utils/bytearray.h" |
|
|
|
#include "base/utils/bytearray.h" |
|
|
|
#include "base/utils/fs.h" |
|
|
|
#include "base/utils/fs.h" |
|
|
|
#include "base/utils/misc.h" |
|
|
|
#include "base/utils/misc.h" |
|
|
@ -335,25 +336,34 @@ void WebApplication::configure() |
|
|
|
m_domainList = pref->getServerDomains().split(';', QString::SkipEmptyParts); |
|
|
|
m_domainList = pref->getServerDomains().split(';', QString::SkipEmptyParts); |
|
|
|
std::for_each(m_domainList.begin(), m_domainList.end(), [](QString &entry) { entry = entry.trimmed(); }); |
|
|
|
std::for_each(m_domainList.begin(), m_domainList.end(), [](QString &entry) { entry = entry.trimmed(); }); |
|
|
|
|
|
|
|
|
|
|
|
m_isClickjackingProtectionEnabled = pref->isWebUiClickjackingProtectionEnabled(); |
|
|
|
|
|
|
|
m_isCSRFProtectionEnabled = pref->isWebUiCSRFProtectionEnabled(); |
|
|
|
m_isCSRFProtectionEnabled = pref->isWebUiCSRFProtectionEnabled(); |
|
|
|
m_isSecureCookieEnabled = pref->isWebUiSecureCookieEnabled(); |
|
|
|
m_isSecureCookieEnabled = pref->isWebUiSecureCookieEnabled(); |
|
|
|
m_isHostHeaderValidationEnabled = pref->isWebUIHostHeaderValidationEnabled(); |
|
|
|
m_isHostHeaderValidationEnabled = pref->isWebUIHostHeaderValidationEnabled(); |
|
|
|
m_isHttpsEnabled = pref->isWebUiHttpsEnabled(); |
|
|
|
m_isHttpsEnabled = pref->isWebUiHttpsEnabled(); |
|
|
|
|
|
|
|
|
|
|
|
m_contentSecurityPolicy = |
|
|
|
m_prebuiltHeaders.clear(); |
|
|
|
|
|
|
|
m_prebuiltHeaders.push_back({QLatin1String(Http::HEADER_X_XSS_PROTECTION), QLatin1String("1; mode=block")}); |
|
|
|
|
|
|
|
m_prebuiltHeaders.push_back({QLatin1String(Http::HEADER_X_CONTENT_TYPE_OPTIONS), QLatin1String("nosniff")}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!m_isAltUIUsed) |
|
|
|
|
|
|
|
m_prebuiltHeaders.push_back({QLatin1String(Http::HEADER_REFERRER_POLICY), QLatin1String("same-origin")}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const bool isClickjackingProtectionEnabled = pref->isWebUiClickjackingProtectionEnabled(); |
|
|
|
|
|
|
|
if (isClickjackingProtectionEnabled) |
|
|
|
|
|
|
|
m_prebuiltHeaders.push_back({QLatin1String(Http::HEADER_X_FRAME_OPTIONS), QLatin1String("SAMEORIGIN")}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const QString contentSecurityPolicy = |
|
|
|
(m_isAltUIUsed |
|
|
|
(m_isAltUIUsed |
|
|
|
? QLatin1String("") |
|
|
|
? QLatin1String("") |
|
|
|
: QLatin1String("default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; script-src 'self' 'unsafe-inline'; object-src 'none'; form-action 'self';")) |
|
|
|
: QLatin1String("default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; script-src 'self' 'unsafe-inline'; object-src 'none'; form-action 'self';")) |
|
|
|
+ (m_isClickjackingProtectionEnabled ? QLatin1String(" frame-ancestors 'self';") : QLatin1String("")) |
|
|
|
+ (isClickjackingProtectionEnabled ? QLatin1String(" frame-ancestors 'self';") : QLatin1String("")) |
|
|
|
+ (m_isHttpsEnabled ? QLatin1String(" upgrade-insecure-requests;") : QLatin1String("")); |
|
|
|
+ (m_isHttpsEnabled ? QLatin1String(" upgrade-insecure-requests;") : QLatin1String("")); |
|
|
|
|
|
|
|
if (!contentSecurityPolicy.isEmpty()) |
|
|
|
|
|
|
|
m_prebuiltHeaders.push_back({QLatin1String(Http::HEADER_CONTENT_SECURITY_POLICY), contentSecurityPolicy}); |
|
|
|
|
|
|
|
|
|
|
|
m_useCustomHTTPHeaders = pref->isWebUICustomHTTPHeadersEnabled(); |
|
|
|
if (pref->isWebUICustomHTTPHeadersEnabled()) { |
|
|
|
m_customHTTPHeaders.clear(); |
|
|
|
|
|
|
|
if (m_useCustomHTTPHeaders) { |
|
|
|
|
|
|
|
const QString customHeaders = pref->getWebUICustomHTTPHeaders().trimmed(); |
|
|
|
const QString customHeaders = pref->getWebUICustomHTTPHeaders().trimmed(); |
|
|
|
const QVector<QStringRef> customHeaderLines = customHeaders.splitRef('\n', QString::SkipEmptyParts); |
|
|
|
const QVector<QStringRef> customHeaderLines = customHeaders.splitRef('\n', QString::SkipEmptyParts); |
|
|
|
m_customHTTPHeaders.reserve(customHeaderLines.size()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (const QStringRef &line : customHeaderLines) { |
|
|
|
for (const QStringRef &line : customHeaderLines) { |
|
|
|
const int idx = line.indexOf(':'); |
|
|
|
const int idx = line.indexOf(':'); |
|
|
@ -365,7 +375,7 @@ void WebApplication::configure() |
|
|
|
|
|
|
|
|
|
|
|
const QString header = line.left(idx).trimmed().toString(); |
|
|
|
const QString header = line.left(idx).trimmed().toString(); |
|
|
|
const QString value = line.mid(idx + 1).trimmed().toString(); |
|
|
|
const QString value = line.mid(idx + 1).trimmed().toString(); |
|
|
|
m_customHTTPHeaders.push_back({header, value}); |
|
|
|
m_prebuiltHeaders.push_back({header, value}); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -391,7 +401,7 @@ void WebApplication::sendFile(const QString &path) |
|
|
|
const auto it = m_translatedFiles.constFind(path); |
|
|
|
const auto it = m_translatedFiles.constFind(path); |
|
|
|
if ((it != m_translatedFiles.constEnd()) && (lastModified <= it->lastModified)) { |
|
|
|
if ((it != m_translatedFiles.constEnd()) && (lastModified <= it->lastModified)) { |
|
|
|
print(it->data, it->mimeType); |
|
|
|
print(it->data, it->mimeType); |
|
|
|
header(Http::HEADER_CACHE_CONTROL, getCachingInterval(it->mimeType)); |
|
|
|
setHeader({Http::HEADER_CACHE_CONTROL, getCachingInterval(it->mimeType)}); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -423,7 +433,7 @@ void WebApplication::sendFile(const QString &path) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
print(data, mimeType.name()); |
|
|
|
print(data, mimeType.name()); |
|
|
|
header(Http::HEADER_CACHE_CONTROL, getCachingInterval(mimeType.name())); |
|
|
|
setHeader({Http::HEADER_CACHE_CONTROL, getCachingInterval(mimeType.name())}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Http::Response WebApplication::processRequest(const Http::Request &request, const Http::Environment &env) |
|
|
|
Http::Response WebApplication::processRequest(const Http::Request &request, const Http::Environment &env) |
|
|
@ -460,22 +470,8 @@ Http::Response WebApplication::processRequest(const Http::Request &request, cons |
|
|
|
print(error.message(), Http::CONTENT_TYPE_TXT); |
|
|
|
print(error.message(), Http::CONTENT_TYPE_TXT); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
header(QLatin1String(Http::HEADER_X_XSS_PROTECTION), QLatin1String("1; mode=block")); |
|
|
|
for (const Http::Header &prebuiltHeader : asConst(m_prebuiltHeaders)) |
|
|
|
header(QLatin1String(Http::HEADER_X_CONTENT_TYPE_OPTIONS), QLatin1String("nosniff")); |
|
|
|
setHeader(prebuiltHeader); |
|
|
|
|
|
|
|
|
|
|
|
if (m_isClickjackingProtectionEnabled) |
|
|
|
|
|
|
|
header(QLatin1String(Http::HEADER_X_FRAME_OPTIONS), QLatin1String("SAMEORIGIN")); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!m_isAltUIUsed) |
|
|
|
|
|
|
|
header(QLatin1String(Http::HEADER_REFERRER_POLICY), QLatin1String("same-origin")); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!m_contentSecurityPolicy.isEmpty()) |
|
|
|
|
|
|
|
header(QLatin1String(Http::HEADER_CONTENT_SECURITY_POLICY), m_contentSecurityPolicy); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (m_useCustomHTTPHeaders) { |
|
|
|
|
|
|
|
for (const CustomHTTPHeader &customHeader : asConst(m_customHTTPHeaders)) |
|
|
|
|
|
|
|
header(customHeader.name, customHeader.value); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return response(); |
|
|
|
return response(); |
|
|
|
} |
|
|
|
} |
|
|
@ -567,7 +563,7 @@ void WebApplication::sessionStart() |
|
|
|
QByteArray cookieRawForm = cookie.toRawForm(); |
|
|
|
QByteArray cookieRawForm = cookie.toRawForm(); |
|
|
|
if (m_isCSRFProtectionEnabled) |
|
|
|
if (m_isCSRFProtectionEnabled) |
|
|
|
cookieRawForm.append("; SameSite=Strict"); |
|
|
|
cookieRawForm.append("; SameSite=Strict"); |
|
|
|
header(Http::HEADER_SET_COOKIE, cookieRawForm); |
|
|
|
setHeader({Http::HEADER_SET_COOKIE, cookieRawForm}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void WebApplication::sessionEnd() |
|
|
|
void WebApplication::sessionEnd() |
|
|
@ -581,7 +577,7 @@ void WebApplication::sessionEnd() |
|
|
|
delete m_sessions.take(m_currentSession->id()); |
|
|
|
delete m_sessions.take(m_currentSession->id()); |
|
|
|
m_currentSession = nullptr; |
|
|
|
m_currentSession = nullptr; |
|
|
|
|
|
|
|
|
|
|
|
header(Http::HEADER_SET_COOKIE, cookie.toRawForm()); |
|
|
|
setHeader({Http::HEADER_SET_COOKIE, cookie.toRawForm()}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool WebApplication::isCrossSiteRequest(const Http::Request &request) const |
|
|
|
bool WebApplication::isCrossSiteRequest(const Http::Request &request) const |
|
|
|