QtPass
2.0.0
Developer documentation
Toggle main menu visibility
Loading...
Searching...
No Matches
pathvalidator.cpp
Go to the documentation of this file.
1
// SPDX-FileCopyrightText: 2014 Anne Jan Brouwer
2
// SPDX-License-Identifier: GPL-3.0-or-later
8
#include "
pathvalidator.h
"
9
#include <QDir>
10
#include <QFileInfo>
11
#include <QStringList>
12
13
auto
PathValidator::isPathInStore
(
const
QString &storeRoot,
14
const
QString &candidate) ->
bool
{
15
return
storeRelativePath
(storeRoot, candidate).has_value();
16
}
17
18
auto
PathValidator::storeRelativePath
(
const
QString &storeRoot,
19
const
QString &candidate)
20
-> std::optional<QString> {
21
if
(storeRoot.isEmpty() || candidate.isEmpty()) {
22
return
std::nullopt;
23
}
24
const
QString rootCanon = QDir(storeRoot).canonicalPath();
25
if
(rootCanon.isEmpty()) {
26
return
std::nullopt;
27
}
28
29
QString resolved;
30
const
QFileInfo fi(QDir::cleanPath(QFileInfo(candidate).absoluteFilePath()));
31
if
(fi.exists()) {
32
resolved = fi.canonicalFilePath();
33
}
else
{
34
// Walk up to the nearest existing ancestor so we can canonicalise it
35
// (resolves any symlinks on the way to the store root), then re-append
36
// the leaf components below that ancestor.
37
QDir parent = fi.dir();
38
QStringList tail;
39
tail.prepend(fi.fileName());
40
while
(!parent.exists()) {
41
tail.prepend(parent.dirName());
42
// The filesystem root always exists, so the loop terminates there
43
// before cdUp() can fail; this guard is defensive against a
44
// pathological QDir that can neither exist nor ascend.
45
if
(!parent.cdUp()) {
46
return
std::nullopt;
47
}
48
}
49
const
QString parentCanon = parent.canonicalPath();
50
if
(parentCanon.isEmpty()) {
51
return
std::nullopt;
52
}
53
resolved = QDir::cleanPath(parentCanon + QLatin1Char(
'/'
) +
54
tail.join(QLatin1Char(
'/'
)));
55
}
56
57
if
(resolved.isEmpty()) {
58
return
std::nullopt;
59
}
60
if
(resolved == rootCanon) {
61
return
QString();
62
}
63
if
(!resolved.startsWith(rootCanon + QLatin1Char(
'/'
))) {
64
return
std::nullopt;
65
}
66
return
resolved.mid(rootCanon.size() + 1);
67
}
68
69
auto
PathValidator::isTargetSpelled
(
const
QString &storeRoot,
70
const
QString &path) ->
bool
{
71
if
(storeRoot.isEmpty() || !QDir::isAbsolutePath(path)) {
72
return
false
;
73
}
74
#ifdef Q_OS_WIN
75
constexpr
auto
cs = Qt::CaseInsensitive;
76
#else
77
constexpr
auto
cs = Qt::CaseSensitive;
78
#endif
79
const
QString root = QDir::cleanPath(storeRoot);
80
const
QString canonical = QDir(root).canonicalPath();
81
if
(canonical.isEmpty() || canonical.compare(root, cs) == 0) {
82
return
false
;
83
}
84
const
auto
atOrUnder = [cs](
const
QString &p,
const
QString &dir) {
85
const
QString prefix =
86
dir.endsWith(QLatin1Char(
'/'
)) ? dir : dir + QLatin1Char(
'/'
);
87
return
p.compare(dir, cs) == 0 || p.startsWith(prefix, cs);
88
};
89
const
QString cleaned = QDir::cleanPath(path);
90
return
!atOrUnder(cleaned, root) && atOrUnder(cleaned, canonical);
91
}
PathValidator::storeRelativePath
static auto storeRelativePath(const QString &storeRoot, const QString &candidate) -> std::optional< QString >
Where candidate lies in the store, judged as isPathInStore() judges it.
Definition
pathvalidator.cpp:18
PathValidator::isPathInStore
static auto isPathInStore(const QString &storeRoot, const QString &candidate) -> bool
Check that a candidate path resolves inside the password store root, after following symlinks and res...
Definition
pathvalidator.cpp:13
PathValidator::isTargetSpelled
static auto isTargetSpelled(const QString &storeRoot, const QString &path) -> bool
Whether path is spelled through the target of a store root that is itself a link, rather than from th...
Definition
pathvalidator.cpp:69
pathvalidator.h
PathValidator: is a path inside the password store, and how is it spelled relative to the store root.
src
pathvalidator.cpp
Generated by
1.18.0