20using namespace Qt::StringLiterals;
24 const QByteArray hostNameAsHex(hostName.toUtf8().toHex());
25 return QString::fromLatin1(hostNameAsHex);
30 const QByteArray hostNameAsUtf8(QByteArray::fromHex(key.toLatin1()));
31 return QString::fromUtf8(hostNameAsUtf8);
34QHstsStore::QHstsStore(
const QString &dirName)
35 : store(absoluteFilePath(dirName), QSettings::IniFormat)
38 store.setFallbacksEnabled(
false);
41QHstsStore::~QHstsStore()
46QList<QHstsPolicy> QHstsStore::readPolicies()
52 QList<QHstsPolicy> policies;
56 const QStringList keys = store.childKeys();
57 for (
const auto &key : keys) {
58 QHstsPolicy restoredPolicy;
59 if (deserializePolicy(key, restoredPolicy)) {
60 restoredPolicy.setHost(settings_key_to_host_name(key));
61 policies.push_back(std::move(restoredPolicy));
62 }
else if (isWritable()) {
72void QHstsStore::addToObserved(
const QHstsPolicy &policy)
74 observedPolicies.push_back(policy);
77void QHstsStore::synchronize()
82 if (observedPolicies.size()) {
84 for (
const QHstsPolicy &policy : std::as_const(observedPolicies)) {
85 const QString key(host_name_to_settings_key(policy.host()));
87 if (policy.isExpired() || !serializePolicy(key, policy))
90 observedPolicies.clear();
97bool QHstsStore::isWritable()
const
99 return store.isWritable();
102QString QHstsStore::absoluteFilePath(
const QString &dirName)
104 const QDir dir(dirName.isEmpty() ? QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
106 return dir.absoluteFilePath(
"hstsstore"_L1);
109void QHstsStore::beginHstsGroups()
111 store.beginGroup(
"StrictTransportSecurity"_L1);
112 store.beginGroup(
"Policies"_L1);
115void QHstsStore::endHstsGroups()
121bool QHstsStore::deserializePolicy(
const QString &key, QHstsPolicy &policy)
123 Q_ASSERT(store.contains(key));
125 const QVariant data(store.value(key));
126 if (data.isNull() || !data.canConvert<QByteArray>())
129 const QByteArray serializedData(data.toByteArray());
130 QDataStream streamer(serializedData);
131 qint64 expiryInMS = 0;
132 if (!(streamer >> expiryInMS))
134 bool includesSubDomains =
false;
135 if (!(streamer >> includesSubDomains))
138 policy.setExpiry(QDateTime::fromMSecsSinceEpoch(expiryInMS));
139 policy.setIncludesSubDomains(includesSubDomains);
144bool QHstsStore::serializePolicy(
const QString &key,
const QHstsPolicy &policy)
146 Q_ASSERT(store.isWritable());
148 QByteArray serializedData;
149 QDataStream streamer(&serializedData, QIODevice::WriteOnly);
150 streamer << policy.expiry().toMSecsSinceEpoch();
151 streamer << policy.includesSubDomains();
153 if (streamer.status() != QDataStream::Ok)
156 store.setValue(key, serializedData);
160void QHstsStore::evictPolicy(
const QString &key)
162 Q_ASSERT(store.isWritable());
163 if (store.contains(key))
static QString settings_key_to_host_name(const QString &key)
static QString host_name_to_settings_key(const QString &hostName)