aboutsummaryrefslogtreecommitdiff
path: root/lib/e2ee/qolmmessage.h
diff options
context:
space:
mode:
authorAlexey Rusakov <Kitsune-Ral@users.sf.net>2022-05-31 13:52:38 +0200
committerAlexey Rusakov <Kitsune-Ral@users.sf.net>2022-05-31 13:52:38 +0200
commita7c43995c3a47bbbac8d862f69f9229eb39f4ed6 (patch)
tree6881a5d9d1dce4990ed094fddc9c059271570f2c /lib/e2ee/qolmmessage.h
parent6e27a49fbbc58a7310753f882fe372ddb0f63e33 (diff)
downloadlibquotient-a7c43995c3a47bbbac8d862f69f9229eb39f4ed6.tar.gz
libquotient-a7c43995c3a47bbbac8d862f69f9229eb39f4ed6.zip
AccountRegistry: fix dropping an inexistent Connection
On Debug builds this would lead to an assertion failure inside Qt.
Diffstat (limited to 'lib/e2ee/qolmmessage.h')
0 files changed, 0 insertions, 0 deletions
d='n124' href='#n124'>124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
// SPDX-FileCopyrightText: 2020 Kitsune Ral <kitsune-ral@users.sf.net>
// SPDX-License-Identifier: LGPL-2.1-or-later

#include "uri.h"

#include "util.h"
#include "logging.h"

#include <QtCore/QRegularExpression>

using namespace Quotient;

namespace {

struct ReplacePair { QLatin1String uriString; char sigil; };
/// \brief Defines bi-directional mapping of path prefixes and sigils
///
/// When there are two prefixes for the same sigil, the first matching
/// entry for a given sigil is used.
const ReplacePair replacePairs[] = {
    { "u/"_ls, '@' },
    { "user/"_ls, '@' },
    { "roomid/"_ls, '!' },
    { "r/"_ls, '#' },
    { "room/"_ls, '#' },
    // The notation for bare event ids is not proposed in MSC2312 but there's
    // https://github.com/matrix-org/matrix-doc/pull/2644
    { "e/"_ls, '$' },
    { "event/"_ls, '$' }
};

}

Uri::Uri(QByteArray primaryId, QByteArray secondaryId, QString query)
{
    if (primaryId.isEmpty())
        primaryType_ = Empty;
    else {
        setScheme("matrix");
        QString pathToBe;
        primaryType_ = Invalid;
        if (primaryId.size() < 2) // There should be something after sigil
            return;
        for (const auto& p: replacePairs)
            if (primaryId[0] == p.sigil) {
                primaryType_ = Type(p.sigil);
                auto safePrimaryId = primaryId.mid(1);
                safePrimaryId.replace('/', "%2F");
                pathToBe = p.uriString + safePrimaryId;
                break;
            }
        if (!secondaryId.isEmpty()) {
            if (secondaryId.size() < 2) {
                primaryType_ = Invalid;
                return;
            }
            auto safeSecondaryId = secondaryId.mid(1);
            safeSecondaryId.replace('/', "%2F");
            pathToBe += "/event/" + safeSecondaryId;
        }
        setPath(pathToBe, QUrl::TolerantMode);
    }
    if (!query.isEmpty())
        setQuery(query);
}

static inline auto encodedPath(const QUrl& url)
{
    return url.path(QUrl::EncodeDelimiters | QUrl::EncodeUnicode);
}

static QString pathSegment(const QUrl& url, int which)
{
    return QUrl::fromPercentEncoding(
        encodedPath(url).section('/', which, which).toUtf8());
}

static auto decodeFragmentPart(QStringView part)
{
    return QUrl::fromPercentEncoding(part.toLatin1()).toUtf8();
}

static inline auto matrixToUrlRegexInit()
{
    // See https://matrix.org/docs/spec/appendices#matrix-to-navigation
    const QRegularExpression MatrixToUrlRE {
        "^/(?<main>[^:]+:[^/?]+)(/(?<sec>(\\$|%24)[^?]+))?(\\?(?<query>.+))?$"
    };
    Q_ASSERT(MatrixToUrlRE.isValid());
    return MatrixToUrlRE;
}

Uri::Uri(QUrl url) : QUrl(std::move(url))
{
    // NB: don't try to use `url` from here on, it's moved-from and empty
    if (isEmpty())
        return; // primaryType_ == Empty

    primaryType_ = Invalid;
    if (!QUrl::isValid()) // MatrixUri::isValid() checks primaryType_
        return;

    if (scheme() == "matrix") {
        // Check sanity as per https://github.com/matrix-org/matrix-doc/pull/2312
        const auto& urlPath = encodedPath(*this);
        const auto& splitPath = urlPath.split('/');
        switch (splitPath.size()) {
        case 2:
            break;
        case 4:
            if (splitPath[2] == "event" || splitPath[2] == "e")
                break;
            [[fallthrough]];
        default:
            return; // Invalid
        }

        for (const auto& p: replacePairs)
            if (urlPath.startsWith(p.uriString)) {
                primaryType_ = Type(p.sigil);
                return; // The only valid return path for matrix: URIs
            }
        qCDebug(MAIN) << "The matrix: URI is not recognised:"
                      << toDisplayString();
        return;
    }

    primaryType_ = NonMatrix; // Default, unless overridden by the code below
    if (scheme() == "https" && authority() == "matrix.to") {
        static const auto MatrixToUrlRE = matrixToUrlRegexInit();
        // matrix.to accepts both literal sigils (as well as & and ? used in
        // its "query" substitute) and their %-encoded forms;
        // so force QUrl to decode everything.
        auto f = fragment(QUrl::EncodeUnicode);
        if (auto&& m = MatrixToUrlRE.match(f); m.hasMatch())
            *this = Uri { decodeFragmentPart(m.capturedView(u"main")),
                          decodeFragmentPart(m.capturedView(u"sec")),
                          decodeFragmentPart(m.capturedView(u"query")) };
    }
}

Uri::Uri(const QString& uriOrId) : Uri(fromUserInput(uriOrId)) {}

Uri Uri::fromUserInput(const QString& uriOrId)
{
    if (uriOrId.isEmpty())
        return {}; // type() == None

    // A quick check if uriOrId is a plain Matrix id