diff options
author | Christian Kandeler <christian.kandeler@qt.io> | 2019-07-23 16:15:57 +0200 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@qt.io> | 2019-07-26 10:41:03 +0000 |
commit | df8ef72aec830d253beef32ee4d9b962afc3346e (patch) | |
tree | 24809b9298550450564688dd75bf77481f4c8971 /src | |
parent | 00bdb007ee7923f79b60c68fb891740af2f598a1 (diff) | |
download | qt-creator-df8ef72aec830d253beef32ee4d9b962afc3346e.tar.gz |
Wizards: Do some input validation on repository URLs
Fixes: QTCREATORBUG-18935
Change-Id: Ie2103cbe2899ea23caaedd4a6350c78b5f380ab9
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
Reviewed-by: André Hartmann <aha_1980@gmx.de>
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/coreplugin/iversioncontrol.cpp | 47 | ||||
-rw-r--r-- | src/plugins/coreplugin/iversioncontrol.h | 13 | ||||
-rw-r--r-- | src/plugins/git/gitclient.cpp | 38 | ||||
-rw-r--r-- | src/plugins/git/gitclient.h | 13 | ||||
-rw-r--r-- | src/plugins/git/gitversioncontrol.cpp | 5 | ||||
-rw-r--r-- | src/plugins/git/gitversioncontrol.h | 2 | ||||
-rw-r--r-- | src/plugins/vcsbase/wizard/vcsjsextension.cpp | 6 | ||||
-rw-r--r-- | src/plugins/vcsbase/wizard/vcsjsextension.h | 1 |
8 files changed, 80 insertions, 45 deletions
diff --git a/src/plugins/coreplugin/iversioncontrol.cpp b/src/plugins/coreplugin/iversioncontrol.cpp index 4a2ade10e7..b8d9582834 100644 --- a/src/plugins/coreplugin/iversioncontrol.cpp +++ b/src/plugins/coreplugin/iversioncontrol.cpp @@ -26,9 +26,12 @@ #include "iversioncontrol.h" #include "vcsmanager.h" +#include <utils/hostosinfo.h> #include <utils/qtcassert.h> +#include <QDir> #include <QFileInfo> +#include <QRegularExpression> #include <QStringList> /*! @@ -90,6 +93,50 @@ ShellCommand *IVersionControl::createInitialCheckoutCommand(const QString &url, return nullptr; } +IVersionControl::RepoUrl::RepoUrl(const QString &location) +{ + if (location.isEmpty()) + return; + + // Check for local remotes (refer to the root or relative path) + // On Windows, local paths typically starts with <drive>: + auto locationIsOnWindowsDrive = [&location] { + if (!Utils::HostOsInfo::isWindowsHost() || location.size() < 2) + return false; + const QChar drive = location.at(0).toLower(); + return drive >= 'a' && drive <= 'z' && location.at(1) == ':'; + }; + if (location.startsWith("file://") || location.startsWith('/') || location.startsWith('.') + || locationIsOnWindowsDrive()) { + protocol = "file"; + path = QDir::fromNativeSeparators(location.startsWith("file://") + ? location.mid(7) : location); + isValid = true; + return; + } + + // TODO: Why not use QUrl? + static const QRegularExpression remotePattern( + "^(?:(?<protocol>[^:]+)://)?(?:(?<user>[^@]+)@)?(?<host>[^:/]+)" + "(?::(?<port>\\d+))?:?(?<path>.*)$"); + const QRegularExpressionMatch match = remotePattern.match(location); + if (!match.hasMatch()) + return; + + bool ok = false; + protocol = match.captured("protocol"); + userName = match.captured("user"); + host = match.captured("host"); + port = match.captured("port").toUShort(&ok); + path = match.captured("path"); + isValid = !host.isEmpty() && (ok || match.captured("port").isEmpty()); +} + +IVersionControl::RepoUrl IVersionControl::getRepoUrl(const QString &location) const +{ + return RepoUrl(location); +} + QString IVersionControl::vcsTopic(const QString &topLevel) { return m_topicCache ? m_topicCache->topic(topLevel) : QString(); diff --git a/src/plugins/coreplugin/iversioncontrol.h b/src/plugins/coreplugin/iversioncontrol.h index 338bab86d8..fb922e7d7a 100644 --- a/src/plugins/coreplugin/iversioncontrol.h +++ b/src/plugins/coreplugin/iversioncontrol.h @@ -217,6 +217,19 @@ public: const QString &localName, const QStringList &extraArgs); + class RepoUrl { + public: + RepoUrl(const QString &location); + + QString protocol; + QString userName; + QString host; + QString path; + quint16 port = 0; + bool isValid = false; + }; + virtual RepoUrl getRepoUrl(const QString &location) const; + signals: void repositoryChanged(const QString &repository); void filesChanged(const QStringList &files); diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 44f4d35f88..8c84c61354 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -3458,44 +3458,10 @@ void GitClient::StashInfo::end() m_stashResult = NotStashed; } -// GitRemote - -GitRemote::GitRemote(const QString &url) +GitRemote::GitRemote(const QString &location) : Core::IVersionControl::RepoUrl(location) { - static const QRegularExpression remotePattern( - "^(?:(?<protocol>[^:]+)://)?(?:(?<user>[^@]+)@)?(?<host>[^:/]+)" - "(?::(?<port>\\d+))?:?(?<path>.*)$"); - - if (url.isEmpty()) - return; - - // Check for local remotes (refer to the root or relative path) - // On Windows, local paths typically starts with <drive>: - auto startsWithWindowsDrive = [](const QString &url) { - if (!HostOsInfo::isWindowsHost() || url.size() < 2) - return false; - const QChar drive = url.at(0).toLower(); - return drive >= 'a' && drive <= 'z' && url.at(1) == ':'; - }; - if (url.startsWith("file://") || url.startsWith('/') || url.startsWith('.') - || startsWithWindowsDrive(url)) { - protocol = "file"; - path = QDir::fromNativeSeparators(url.startsWith("file://") ? url.mid(7) : url); + if (isValid && protocol == "file") isValid = QDir(path).exists() || QDir(path + ".git").exists(); - return; - } - - const QRegularExpressionMatch match = remotePattern.match(url); - if (!match.hasMatch()) - return; - - bool ok = false; - protocol = match.captured("protocol"); - userName = match.captured("user"); - host = match.captured("host"); - port = match.captured("port").toUShort(&ok); - path = match.captured("path"); - isValid = ok || match.captured("port").isEmpty(); } } // namespace Internal diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index c5e9a0df4f..32f7ac0e25 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -29,6 +29,7 @@ #include "commitdata.h" #include <coreplugin/editormanager/ieditor.h> +#include <coreplugin/iversioncontrol.h> #include <vcsbase/vcsbaseclient.h> #include <utils/fileutils.h> @@ -381,16 +382,10 @@ private: QFutureSynchronizer<void> m_synchronizer; // for commit updates }; -class GitRemote { +class GitRemote : public Core::IVersionControl::RepoUrl +{ public: - GitRemote(const QString &url); - - QString protocol; - QString userName; - QString host; - QString path; - quint16 port = 0; - bool isValid = false; + GitRemote(const QString &location); }; } // namespace Internal diff --git a/src/plugins/git/gitversioncontrol.cpp b/src/plugins/git/gitversioncontrol.cpp index 38231527b2..8325a298b0 100644 --- a/src/plugins/git/gitversioncontrol.cpp +++ b/src/plugins/git/gitversioncontrol.cpp @@ -163,6 +163,11 @@ Core::ShellCommand *GitVersionControl::createInitialCheckoutCommand(const QStrin return command; } +GitVersionControl::RepoUrl GitVersionControl::getRepoUrl(const QString &location) const +{ + return GitRemote(location); +} + QStringList GitVersionControl::additionalToolsPath() const { QStringList res = m_client->settings().searchPathList(); diff --git a/src/plugins/git/gitversioncontrol.h b/src/plugins/git/gitversioncontrol.h index 1e1025864d..7985040f8e 100644 --- a/src/plugins/git/gitversioncontrol.h +++ b/src/plugins/git/gitversioncontrol.h @@ -63,6 +63,8 @@ public: const QString &localName, const QStringList &extraArgs) final; + RepoUrl getRepoUrl(const QString &location) const override; + QStringList additionalToolsPath() const final; void emitFilesChanged(const QStringList &); diff --git a/src/plugins/vcsbase/wizard/vcsjsextension.cpp b/src/plugins/vcsbase/wizard/vcsjsextension.cpp index bb781a32ad..35f73ae8a1 100644 --- a/src/plugins/vcsbase/wizard/vcsjsextension.cpp +++ b/src/plugins/vcsbase/wizard/vcsjsextension.cpp @@ -45,5 +45,11 @@ QString VcsJsExtension::displayName(const QString &vcsId) const return vc ? vc->displayName() : QString(); } +bool VcsJsExtension::isValidRepoUrl(const QString &vcsId, const QString &location) const +{ + const IVersionControl * const vc = VcsManager::versionControl(Id::fromString(vcsId)); + return vc && vc->getRepoUrl(location).isValid; +} + } // namespace Internal } // namespace VcsBase diff --git a/src/plugins/vcsbase/wizard/vcsjsextension.h b/src/plugins/vcsbase/wizard/vcsjsextension.h index 4882a198d7..e1b5198cd9 100644 --- a/src/plugins/vcsbase/wizard/vcsjsextension.h +++ b/src/plugins/vcsbase/wizard/vcsjsextension.h @@ -37,6 +37,7 @@ class VcsJsExtension : public QObject public: Q_INVOKABLE bool isConfigured(const QString &vcsId) const; Q_INVOKABLE QString displayName(const QString &vcsId) const; + Q_INVOKABLE bool isValidRepoUrl(const QString &vcsId, const QString &location) const; }; } // namespace Internal |