Skip to content
Permalink
Browse files

Be more stringent about properly escaping external strings in HTML ('…

…rich text' in Qt-speak).

This commit ensures that external-ish strings are escaped
using Qt::escape before being used in a rich text (HTML)
context.

This patch focuses on QMessageBox's body text, the Mumble log,
and tooltip texts.

Fixes #1208
  • Loading branch information...
bontibon authored and mkrautz committed Apr 5, 2014
1 parent 9946dc7 commit b7d9387bd6dacbad0b2345f03dd8502a51c42f6a
@@ -362,7 +362,7 @@ void ALSAAudioInput::run() {
snd_pcm_close(capture_handle);
capture_handle = NULL;
}
g.mw->msgBox(tr("Opening chosen ALSA Input failed: %1").arg(QLatin1String(snd_strerror(err))));
g.mw->msgBox(tr("Opening chosen ALSA Input failed: %1").arg(Qt::escape(QLatin1String(snd_strerror(err)))));
return;
}

@@ -497,7 +497,7 @@ void ALSAAudioOutput::run() {
snd_pcm_writei(pcm_handle, zerobuff, period_size);

if (! bOk) {
g.mw->msgBox(tr("Opening chosen ALSA Output failed: %1").arg(QLatin1String(snd_strerror(err))));
g.mw->msgBox(tr("Opening chosen ALSA Output failed: %1").arg(Qt::escape(QLatin1String(snd_strerror(err)))));
if (pcm_handle) {
snd_pcm_close(pcm_handle);
pcm_handle = NULL;
@@ -268,7 +268,7 @@ void ASIOConfig::on_qpbQuery_clicked() {
char err[255];
iasio->getErrorMessage(err);
SleepEx(10, false);
QMessageBox::critical(this, QLatin1String("Mumble"), tr("ASIO Initialization failed: %1").arg(QLatin1String(err)), QMessageBox::Ok, QMessageBox::NoButton);
QMessageBox::critical(this, QLatin1String("Mumble"), tr("ASIO Initialization failed: %1").arg(Qt::escape(QLatin1String(err))), QMessageBox::Ok, QMessageBox::NoButton);
}
iasio->Release();
} else {
@@ -293,7 +293,7 @@ void ASIOConfig::on_qpbConfig_clicked() {
char err[255];
iasio->getErrorMessage(err);
SleepEx(10, false);
QMessageBox::critical(this, QLatin1String("Mumble"), tr("ASIO Initialization failed: %1").arg(QLatin1String(err)), QMessageBox::Ok, QMessageBox::NoButton);
QMessageBox::critical(this, QLatin1String("Mumble"), tr("ASIO Initialization failed: %1").arg(Qt::escape(QLatin1String(err))), QMessageBox::Ok, QMessageBox::NoButton);
}
iasio->Release();
} else {
@@ -370,7 +370,7 @@ void AudioInputDialog::on_qcbSystem_currentIndexChanged(int) {

foreach(audioDevice d, ql) {
qcbDevice->addItem(d.first, d.second);
qcbDevice->setItemData(idx, d.first, Qt::ToolTipRole);
qcbDevice->setItemData(idx, Qt::escape(d.first), Qt::ToolTipRole);
++idx;
}

@@ -516,7 +516,7 @@ void AudioOutputDialog::on_qcbSystem_currentIndexChanged(int) {

foreach(audioDevice d, ql) {
qcbDevice->addItem(d.first, d.second);
qcbDevice->setItemData(idx, d.first, Qt::ToolTipRole);
qcbDevice->setItemData(idx, Qt::escape(d.first), Qt::ToolTipRole);
++idx;
}
bool canmute = aor->canMuteOthers();
@@ -462,7 +462,7 @@ QVariant ServerItem::data(int column, int role) const {
} else if (role == Qt::ToolTipRole) {
QStringList qsl;
foreach(const QHostAddress &qha, qlAddresses)
qsl << qha.toString();
qsl << Qt::escape(qha.toString());

double ploss = 100.0;

@@ -472,18 +472,18 @@ QVariant ServerItem::data(int column, int role) const {
QString qs;
qs +=
QLatin1String("<table>") +
QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Servername"), qsName) +
QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Hostname"), qsHostname);
QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Servername"), Qt::escape(qsName)) +
QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Hostname"), Qt::escape(qsHostname));

if (! qsBonjourHost.isEmpty())
qs += QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Bonjour name"), qsBonjourHost);
qs += QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Bonjour name"), Qt::escape(qsBonjourHost));

qs +=
QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Port")).arg(usPort) +
QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Addresses"), qsl.join(QLatin1String(", ")));

if (! qsUrl.isEmpty())
qs += QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Website"), qsUrl);
qs += QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Website"), Qt::escape(qsUrl));

if (uiSent > 0) {
qs += QString::fromLatin1("<tr><th align=left>%1</th><td>%2</td></tr>").arg(ConnectDialog::tr("Packet loss"), QString::fromLatin1("%1% (%2/%3)").arg(ploss, 0, 'f', 1).arg(uiRecv).arg(uiSent));
@@ -122,7 +122,7 @@ Database::Database() {
QFileInfo fi(db.databaseName());

if (! fi.isWritable()) {
QMessageBox::critical(NULL, QLatin1String("Mumble"), tr("The database '%1' is read-only. Mumble cannot store server settings (i.e. SSL certificates) until you fix this problem.").arg(fi.filePath()), QMessageBox::Ok | QMessageBox::Default, QMessageBox::NoButton);
QMessageBox::critical(NULL, QLatin1String("Mumble"), tr("The database '%1' is read-only. Mumble cannot store server settings (i.e. SSL certificates) until you fix this problem.").arg(Qt::escape(fi.filePath())), QMessageBox::Ok | QMessageBox::Default, QMessageBox::NoButton);
qWarning("Database: Database is read-only");
}

@@ -111,7 +111,7 @@ LCDConfig::LCDConfig(Settings &st) : ConfigWidget(st) {
qtwi->setFlags(Qt::ItemIsEnabled |Qt::ItemIsUserCheckable);

qtwi->setText(0, d->name());
qtwi->setToolTip(0, d->name());
qtwi->setToolTip(0, Qt::escape(d->name()));

QSize lcdsize = d->size();
QString qsSize = QString::fromLatin1("%1x%2").arg(lcdsize.width()).arg(lcdsize.height());
@@ -263,7 +263,7 @@ QString Log::msgColor(const QString &text, LogColorType t) {
}

QString Log::formatChannel(::Channel *c) {
return QString::fromLatin1("<a href='channelid://%1/%3' class='log-channel'>%2</a>").arg(c->iId).arg(c->qsName).arg(QString::fromLatin1(g.sh->qbaDigest.toBase64()));
return QString::fromLatin1("<a href='channelid://%1/%3' class='log-channel'>%2</a>").arg(c->iId).arg(Qt::escape(c->qsName)).arg(QString::fromLatin1(g.sh->qbaDigest.toBase64()));
}

QString Log::formatClientUser(ClientUser *cu, LogColorType t) {
@@ -275,10 +275,11 @@ QString Log::formatClientUser(ClientUser *cu, LogColorType t) {
}

if (cu) {
QString name = Qt::escape(cu->qsName);
if (cu->qsHash.isEmpty()) {
return QString::fromLatin1("<a href='clientid://%2/%4' class='log-user log-%1'>%3</a>").arg(className).arg(cu->uiSession).arg(cu->qsName).arg(QString::fromLatin1(g.sh->qbaDigest.toBase64()));
return QString::fromLatin1("<a href='clientid://%2/%4' class='log-user log-%1'>%3</a>").arg(className).arg(cu->uiSession).arg(name).arg(QString::fromLatin1(g.sh->qbaDigest.toBase64()));
} else {
return QString::fromLatin1("<a href='clientid://%2' class='log-user log-%1'>%3</a>").arg(className).arg(cu->qsHash).arg(cu->qsName);
return QString::fromLatin1("<a href='clientid://%2' class='log-user log-%1'>%3</a>").arg(className).arg(cu->qsHash).arg(name);
}
} else {
return QString::fromLatin1("<span class='log-server log-%1'>%2</span>").arg(className).arg(tr("the server"));
@@ -619,7 +619,7 @@ static void recreateServerHandler() {
}

void MainWindow::openUrl(const QUrl &url) {
g.l->log(Log::Information, tr("Opening URL %1").arg(url.toString()));
g.l->log(Log::Information, tr("Opening URL %1").arg(Qt::escape(url.toString())));
if (url.scheme() == QLatin1String("file")) {
QFile f(url.toLocalFile());
if (! f.exists() || ! f.open(QIODevice::ReadOnly)) {
@@ -992,7 +992,7 @@ void MainWindow::on_qaSelfRegister_triggered() {
return;

QMessageBox::StandardButton result;
result = QMessageBox::question(this, tr("Register yourself as %1").arg(p->qsName), tr("<p>You are about to register yourself on this server. This action cannot be undone, and your username cannot be changed once this is done. You will forever be known as '%1' on this server.</p><p>Are you sure you want to register yourself?</p>").arg(p->qsName), QMessageBox::Yes|QMessageBox::No);
result = QMessageBox::question(this, tr("Register yourself as %1").arg(p->qsName), tr("<p>You are about to register yourself on this server. This action cannot be undone, and your username cannot be changed once this is done. You will forever be known as '%1' on this server.</p><p>Are you sure you want to register yourself?</p>").arg(Qt::escape(p->qsName)), QMessageBox::Yes|QMessageBox::No);

if (result == QMessageBox::Yes)
g.sh->registerUser(p->uiSession);
@@ -1077,7 +1077,7 @@ void MainWindow::on_qaServerInformation_triggered() {
qsVersion.append(tr("<p>No build information or OS version available.</p>"));
} else {
qsVersion.append(tr("<p>%1 (%2)<br />%3</p>")
.arg(g.sh->qsRelease, g.sh->qsOS, g.sh->qsOSVersion));
.arg(Qt::escape(g.sh->qsRelease), Qt::escape(g.sh->qsOS), Qt::escape(g.sh->qsOSVersion)));
}

QString host, uname, pw;
@@ -1086,7 +1086,7 @@ void MainWindow::on_qaServerInformation_triggered() {
g.sh->getConnectionInfo(host,port,uname,pw);

QString qsControl=tr("<h2>Control channel</h2><p>Encrypted with %1 bit %2<br />%3 ms average latency (%4 deviation)</p><p>Remote host %5 (port %6)</p>").arg(QString::number(qsc.usedBits()),
qsc.name(),
Qt::escape(qsc.name()),
QString::fromLatin1("%1").arg(boost::accumulators::mean(g.sh->accTCP), 0, 'f', 2),
QString::fromLatin1("%1").arg(sqrt(boost::accumulators::variance(g.sh->accTCP)),0,'f',2),
host,
@@ -1346,9 +1346,9 @@ void MainWindow::on_qaUserRegister_triggered() {
QMessageBox::StandardButton result;

if (session == g.uiSession)
result = QMessageBox::question(this, tr("Register yourself as %1").arg(p->qsName), tr("<p>You are about to register yourself on this server. This action cannot be undone, and your username cannot be changed once this is done. You will forever be known as '%1' on this server.</p><p>Are you sure you want to register yourself?</p>").arg(p->qsName), QMessageBox::Yes|QMessageBox::No);
result = QMessageBox::question(this, tr("Register yourself as %1").arg(p->qsName), tr("<p>You are about to register yourself on this server. This action cannot be undone, and your username cannot be changed once this is done. You will forever be known as '%1' on this server.</p><p>Are you sure you want to register yourself?</p>").arg(Qt::escape(p->qsName)), QMessageBox::Yes|QMessageBox::No);
else
result = QMessageBox::question(this, tr("Register user %1").arg(p->qsName), tr("<p>You are about to register %1 on the server. This action cannot be undone, the username cannot be changed, and as a registered user, %1 will have access to the server even if you change the server password.</p><p>From this point on, %1 will be authenticated with the certificate currently in use.</p><p>Are you sure you want to register %1?</p>").arg(p->qsName), QMessageBox::Yes|QMessageBox::No);
result = QMessageBox::question(this, tr("Register user %1").arg(p->qsName), tr("<p>You are about to register %1 on the server. This action cannot be undone, the username cannot be changed, and as a registered user, %1 will have access to the server even if you change the server password.</p><p>From this point on, %1 will be authenticated with the certificate currently in use.</p><p>Are you sure you want to register %1?</p>").arg(Qt::escape(p->qsName)), QMessageBox::Yes|QMessageBox::No);

if (result == QMessageBox::Yes) {
p = ClientUser::get(session);
@@ -1484,7 +1484,7 @@ void MainWindow::on_qaUserCommentReset_triggered() {
unsigned int session = p->uiSession;

int ret = QMessageBox::question(this, QLatin1String("Mumble"),
tr("Are you sure you want to reset the comment of user %1?").arg(p->qsName),
tr("Are you sure you want to reset the comment of user %1?").arg(Qt::escape(p->qsName)),
QMessageBox::Yes, QMessageBox::No);
if (ret == QMessageBox::Yes) {
g.sh->setUserComment(session, QString());
@@ -1705,7 +1705,7 @@ void MainWindow::on_qaChannelRemove_triggered() {

int id = c->iId;

ret=QMessageBox::question(this, QLatin1String("Mumble"), tr("Are you sure you want to delete %1 and all its sub-channels?").arg(c->qsName), QMessageBox::Yes, QMessageBox::No);
ret=QMessageBox::question(this, QLatin1String("Mumble"), tr("Are you sure you want to delete %1 and all its sub-channels?").arg(Qt::escape(c->qsName)), QMessageBox::Yes, QMessageBox::No);

c = Channel::get(id);
if (!c)
@@ -2519,7 +2519,7 @@ void MainWindow::serverDisconnected(QAbstractSocket::SocketError err, QString re

if (! g.sh->qlErrors.isEmpty()) {
foreach(QSslError e, g.sh->qlErrors)
g.l->log(Log::Warning, tr("SSL Verification failed: %1").arg(e.errorString()));
g.l->log(Log::Warning, tr("SSL Verification failed: %1").arg(Qt::escape(e.errorString())));
if (! g.sh->qscCert.isEmpty()) {
QSslCertificate c = g.sh->qscCert.at(0);
QString basereason;
@@ -2530,7 +2530,7 @@ void MainWindow::serverDisconnected(QAbstractSocket::SocketError err, QString re
}
QStringList qsl;
foreach(QSslError e, g.sh->qlErrors)
qsl << QString::fromLatin1("<li>%1</li>").arg(e.errorString());
qsl << QString::fromLatin1("<li>%1</li>").arg(Qt::escape(e.errorString()));

QMessageBox qmb(QMessageBox::Warning, QLatin1String("Mumble"),
tr("<p>%1.<br />The specific errors with this certificate are: </p><ol>%2</ol>"
@@ -2563,7 +2563,7 @@ void MainWindow::serverDisconnected(QAbstractSocket::SocketError err, QString re


if (! reason.isEmpty()) {
g.l->log(Log::ServerDisconnected, tr("Server connection failed: %1.").arg(reason));
g.l->log(Log::ServerDisconnected, tr("Server connection failed: %1.").arg(Qt::escape(reason)));
} else {
g.l->log(Log::ServerDisconnected, tr("Disconnected from server."));
}
@@ -2710,10 +2710,10 @@ void MainWindow::updateChatBar() {
if (!g.s.bChatBarUseSelection || c == NULL) // If no channel selected fallback to current one
c = ClientUser::get(g.uiSession)->cChannel;

qteChat->setDefaultText(tr("<center>Type message to channel '%1' here</center>").arg(c->qsName));
qteChat->setDefaultText(tr("<center>Type message to channel '%1' here</center>").arg(Qt::escape(c->qsName)));
} else {
// User target
qteChat->setDefaultText(tr("<center>Type message to user '%1' here</center>").arg(p->qsName));
qteChat->setDefaultText(tr("<center>Type message to user '%1' here</center>").arg(Qt::escape(p->qsName)));
}

updateMenuPermissions();
@@ -110,7 +110,7 @@ void MainWindow::msgReject(const MumbleProto::Reject &msg) {
break;
}

g.l->log(Log::ServerDisconnected, tr("Server connection rejected: %1.").arg(reason));
g.l->log(Log::ServerDisconnected, tr("Server connection rejected: %1.").arg(Qt::escape(reason)));
g.l->setIgnore(Log::ServerDisconnected, 1);
}

@@ -156,7 +156,7 @@ void MainWindow::msgServerSync(const MumbleProto::ServerSync &msg) {
connect(user, SIGNAL(prioritySpeakerStateChanged()), this, SLOT(userStateChanged()));
connect(user, SIGNAL(recordingStateChanged()), this, SLOT(userStateChanged()));

qstiIcon->setToolTip(tr("Mumble: %1").arg(Channel::get(0)->qsName));
qstiIcon->setToolTip(tr("Mumble: %1").arg(Qt::escape(Channel::get(0)->qsName)));

// Update QActions and menues
on_qmServer_aboutToShow();
@@ -217,7 +217,7 @@ void MainWindow::msgPermissionDenied(const MumbleProto::PermissionDenied &msg) {
g.s.bTTS = true;
quint32 oflags = g.s.qmMessages.value(Log::PermissionDenied);
g.s.qmMessages[Log::PermissionDenied] = (oflags | Settings::LogTTS) & (~Settings::LogSoundfile);
g.l->log(Log::PermissionDenied, QString::fromUtf8(g.ccHappyEaster + 39).arg(g.s.qsUsername));
g.l->log(Log::PermissionDenied, QString::fromUtf8(g.ccHappyEaster + 39).arg(Qt::escape(g.s.qsUsername)));
g.s.qmMessages[Log::PermissionDenied] = oflags;
g.s.bDeaf = bold;
g.s.bTTS = bold2;
@@ -242,7 +242,7 @@ void MainWindow::msgPermissionDenied(const MumbleProto::PermissionDenied &msg) {
break;
case MumbleProto::PermissionDenied_DenyType_UserName: {
if (msg.has_name())
g.l->log(Log::PermissionDenied, tr("Invalid username: %1.").arg(u8(msg.name())));
g.l->log(Log::PermissionDenied, tr("Invalid username: %1.").arg(Qt::escape(u8(msg.name()))));
else
g.l->log(Log::PermissionDenied, tr("Invalid username."));
}
@@ -257,7 +257,7 @@ void MainWindow::msgPermissionDenied(const MumbleProto::PermissionDenied &msg) {
break;
default: {
if (msg.has_reason())
g.l->log(Log::PermissionDenied, tr("Denied: %1.").arg(u8(msg.reason())));
g.l->log(Log::PermissionDenied, tr("Denied: %1.").arg(Qt::escape(u8(msg.reason()))));
else
g.l->log(Log::PermissionDenied, tr("Permission denied."));
}
@@ -507,7 +507,7 @@ void MainWindow::msgUserRemove(const MumbleProto::UserRemove &msg) {
ACTOR_INIT;
SELF_INIT;

QString reason = u8(msg.reason());
QString reason = Qt::escape(u8(msg.reason()));

if (pDst == pSelf) {
if (msg.ban())
@@ -102,7 +102,7 @@ Overlay::Overlay() : QObject() {
#endif

if (! qlsServer->listen(pipepath)) {
QMessageBox::warning(NULL, QLatin1String("Mumble"), tr("Failed to create communication with overlay at %2: %1. No overlay will be available.").arg(qlsServer->errorString(),pipepath), QMessageBox::Ok, QMessageBox::NoButton);
QMessageBox::warning(NULL, QLatin1String("Mumble"), tr("Failed to create communication with overlay at %2: %1. No overlay will be available.").arg(Qt::escape(qlsServer->errorString()), Qt::escape(pipepath)), QMessageBox::Ok, QMessageBox::NoButton);
} else {
qWarning() << "Overlay: Listening on" << qlsServer->fullServerName();
connect(qlsServer, SIGNAL(newConnection()), this, SLOT(newConnection()));
@@ -195,7 +195,7 @@ void PluginConfig::refillPluginList() {
i->setCheckState(1, pi->enabled ? Qt::Checked : Qt::Unchecked);
i->setText(0, pi->description);
if (pi->p->longdesc)
i->setToolTip(0, QString::fromStdWString(pi->p->longdesc()));
i->setToolTip(0, Qt::escape(QString::fromStdWString(pi->p->longdesc())));
i->setData(0, Qt::UserRole, pi->filename);
}
qtwPlugins->setCurrentItem(qtwPlugins->topLevelItem(0));
@@ -411,7 +411,7 @@ void Plugins::on_Timer_timeout() {
QReadLocker lock(&qrwlPlugins);

if (prevlocked) {
g.l->log(Log::Information, tr("%1 lost link.").arg(prevlocked->shortname));
g.l->log(Log::Information, tr("%1 lost link.").arg(Qt::escape(prevlocked->shortname)));
prevlocked = NULL;
}

@@ -485,7 +485,7 @@ void Plugins::on_Timer_timeout() {
if (pi->enabled) {
if (pi->p2 ? pi->p2->trylock(pids) : pi->p->trylock()) {
pi->shortname = QString::fromStdWString(pi->p->shortname);
g.l->log(Log::Information, tr("%1 linked.").arg(pi->shortname));
g.l->log(Log::Information, tr("%1 linked.").arg(Qt::escape(pi->shortname)));
pi->locked = true;
bUnlink = false;
locked = pi;
@@ -685,15 +685,15 @@ void Plugins::fetched(QByteArray data, QUrl url) {
if (f.open(QIODevice::WriteOnly)) {
f.write(data);
f.close();
g.mw->msgBox(tr("Downloaded new or updated plugin to %1.").arg(f.fileName()));
g.mw->msgBox(tr("Downloaded new or updated plugin to %1.").arg(Qt::escape(f.fileName())));
} else {
f.setFileName(qsUserPlugins + QLatin1String("/") + fname);
if (f.open(QIODevice::WriteOnly)) {
f.write(data);
f.close();
g.mw->msgBox(tr("Downloaded new or updated plugin to %1.").arg(f.fileName()));
g.mw->msgBox(tr("Downloaded new or updated plugin to %1.").arg(Qt::escape(f.fileName())));
} else {
g.mw->msgBox(tr("Failed to install new plugin to %1.").arg(f.fileName()));
g.mw->msgBox(tr("Failed to install new plugin to %1.").arg(Qt::escape(f.fileName())));
}
}

1 comment on commit b7d9387

@hacst

This comment has been minimized.

Copy link
Member

commented on b7d9387 Apr 27, 2014

Please sign in to comment.
You can’t perform that action at this time.