Browse Source

Bound avatar manifest sizes before numeric conversion

master
evgeny 4 days ago
parent
commit
52f4628fe0
  1. 5
      tools/chatgui/src/avatars/avatarcache.cpp
  2. 9
      tools/chatgui/tests/test_avatars.cpp

5
tools/chatgui/src/avatars/avatarcache.cpp

@ -51,13 +51,14 @@ AvatarCache::Result AvatarCache::readObject(const QString& path, const QString&
if (name.endsWith(".json")) {
const QJsonObject o = QJsonDocument::fromJson(bytes).object(); Record& r = result.record;
r.original = o["original"].toString(); r.preview = o["preview"].toString();
r.originalBytes = qint64(o["original_bytes"].toDouble()); r.previewBytes = qint64(o["preview_bytes"].toDouble());
r.originalBytes = qint64(qBound(-1.0, o["original_bytes"].toDouble(-1), double(OriginalMaxBytes) + 1));
r.previewBytes = qint64(qBound(-1.0, o["preview_bytes"].toDouble(-1), double(MaxBytes) + 1));
r.size = QSize(o["width"].toInt(), o["height"].toInt());
r.crop = QRectF(o["x"].toDouble(-1), o["y"].toDouble(-1), o["w"].toDouble(), o["h"].toDouble());
const double pixelW = r.crop.width() * r.size.width(), pixelH = r.crop.height() * r.size.height();
if (o["version"].toInt() != 1 || !mf_avatar_file_valid(r.original.toLatin1().constData()) || r.original.endsWith(".json") ||
!mf_avatar_file_valid(r.preview.toLatin1().constData()) || !r.preview.endsWith(".webp") ||
!r.size.isValid() || qint64(r.size.width()) * r.size.height() > 16 * 1024 * 1024 ||
r.size.width() <= 0 || r.size.height() <= 0 || qint64(r.size.width()) * r.size.height() > 16 * 1024 * 1024 ||
r.originalBytes < 1 || r.originalBytes > OriginalMaxBytes || r.previewBytes < 1 || r.previewBytes > MaxBytes ||
!r.crop.isValid() || !QRectF(0, 0, 1, 1).contains(r.crop) || qAbs(pixelW - pixelH) > 2) {
result.error = "invalid avatar manifest"; r = {};

9
tools/chatgui/tests/test_avatars.cpp

@ -12,6 +12,8 @@
#include <QPainter>
#include <QDialog>
#include <QPushButton>
#include <QJsonDocument>
#include <QJsonObject>
extern "C" {
#include "utun_instance.h"
#include "chat/chat_core.h"
@ -77,6 +79,13 @@ private slots:
QFile webp(directory.path() + '/' + prepared.record.preview); QVERIFY(webp.open(QIODevice::ReadOnly));
const QByteArray encoded=webp.readAll(); QCOMPARE(encoded.left(4),QByteArray("RIFF")); QVERIFY(encoded.contains("VP8 "));
QVERIFY(!AvatarCache::load(path, prepared.hash).image.isNull());
QFile description(path); QVERIFY(description.open(QIODevice::ReadOnly));
QJsonObject record=QJsonDocument::fromJson(description.readAll()).object(); description.close();
record["original_bytes"]=1e99;
const QByteArray oversized=QJsonDocument(record).toJson(QJsonDocument::Compact);
const QString oversizedName=QCryptographicHash::hash(oversized,QCryptographicHash::Sha256).toHex()+".json";
QString writeError; QVERIFY(AvatarCache::storeObject(directory.path(),oversizedName,oversized,writeError));
QVERIFY(!AvatarCache::readObject(directory.path()+'/'+oversizedName,oversizedName).error.isEmpty());
QVERIFY(AvatarCache::load(path, QString(64, '0')).image.isNull());
QFile corrupt(path); QVERIFY(corrupt.open(QIODevice::Append)); QCOMPARE(corrupt.write("x"), 1LL); corrupt.close();
QVERIFY(AvatarCache::load(path, prepared.hash).image.isNull());

Loading…
Cancel
Save