eventmanager.cpp
identity.cpp
ignorelistmanager.cpp
- internalconnection.cpp
+ internalpeer.cpp
ircchannel.cpp
ircevent.cpp
irclisthelper.cpp
networkconfig.cpp
networkevent.cpp
quassel.cpp
- remoteconnection.cpp
+ remotepeer.cpp
settings.cpp
signalproxy.cpp
syncableobject.cpp
util.cpp
- protocols/legacy/legacyconnection.cpp
+ protocols/legacy/legacypeer.cpp
)
set(MOC_HDRS
eventmanager.h
identity.h
ignorelistmanager.h
- internalconnection.h
+ internalpeer.h
ircchannel.h
irclisthelper.h
ircuser.h
network.h
networkconfig.h
- remoteconnection.h
+ remotepeer.h
settings.h
signalproxy.h
syncableobject.h
- protocols/legacy/legacyconnection.h
+ protocols/legacy/legacypeer.h
)
set(HEADERS ${MOC_HDRS}
networkevent.h
logger.h
message.h
+ protocol.h
types.h
util.h)
+ if (HAVE_QCA2)
+ set(SOURCES ${SOURCES} keyevent.cpp)
+ set(HEADERS ${HEADERS} keyevent.h)
+ endif(HAVE_QCA2)
+
if(APPLE)
set(SOURCES ${SOURCES} mac_utils.cpp)
set(HEADERS ${HEADERS} mac_utils.h)
/***************************************************************************
- * Copyright (C) 2005-2012 by the Quassel Project *
+ * Copyright (C) 2005-2013 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
CtcpEvent = 0x00050000,
CtcpEventFlush
+
+ #ifdef HAVE_QCA2
+ ,KeyEvent = 0x00060000
+ #endif
};
EventManager(QObject *parent = 0);
/***************************************************************************
- * Copyright (C) 2005-2012 by the Quassel Project *
+ * Copyright (C) 2005-2013 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
if (topic().isEmpty())
return;
- QByteArray key = qobject_cast<CoreNetwork *>(network())->cipherKey(name());
- if (key.isEmpty())
- return;
-
- if (!cipher()->setKey(key))
- return;
-
QByteArray decrypted = cipher()->decryptTopic(topic().toAscii());
setTopic(decodeString(decrypted));
}
/***************************************************************************
- * Copyright (C) 2005-2012 by the Quassel Project *
+ * Copyright (C) 2005-2013 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
#ifdef HAVE_QCA2
- Cipher *CoreNetwork::cipher(const QString &target) const
+ Cipher *CoreNetwork::cipher(const QString &target)
{
if (target.isEmpty())
return 0;
if (!Cipher::neededFeaturesAvailable())
return 0;
- QByteArray key = cipherKey(target);
- if (key.isEmpty())
- return 0;
-
CoreIrcChannel *channel = qobject_cast<CoreIrcChannel *>(ircChannel(target));
if (channel) {
- if (channel->cipher()->setKey(key))
- return channel->cipher();
+ return channel->cipher();
}
- else {
- CoreIrcUser *user = qobject_cast<CoreIrcUser *>(ircUser(target));
- if (user && user->cipher()->setKey(key))
- return user->cipher();
+ CoreIrcUser *user = qobject_cast<CoreIrcUser *>(ircUser(target));
+ if (user) {
+ return user->cipher();
+ } else if (!isChannelName(target)) {
+ return qobject_cast<CoreIrcUser*>(newIrcUser(target))->cipher();
}
return 0;
}
- QByteArray CoreNetwork::cipherKey(const QString &recipient) const
+ QByteArray CoreNetwork::cipherKey(const QString &target) const
{
- return _cipherKeys.value(recipient.toLower(), QByteArray());
+ CoreIrcChannel *c = qobject_cast<CoreIrcChannel*>(ircChannel(target));
+ if (c)
+ return c->cipher()->key();
+
+ CoreIrcUser *u = qobject_cast<CoreIrcUser*>(ircUser(target));
+ if (u)
+ return u->cipher()->key();
+
+ return QByteArray();
}
- void CoreNetwork::setCipherKey(const QString &recipient, const QByteArray &key)
+ void CoreNetwork::setCipherKey(const QString &target, const QByteArray &key)
{
- if (!key.isEmpty())
- _cipherKeys[recipient.toLower()] = key;
- else
- _cipherKeys.remove(recipient.toLower());
- }
+ CoreIrcChannel *c = qobject_cast<CoreIrcChannel*>(ircChannel(target));
+ if (c) {
+ c->setEncrypted(c->cipher()->setKey(key));
+ return;
+ }
+ CoreIrcUser *u = qobject_cast<CoreIrcUser*>(ircUser(target));
+ if (!u && !isChannelName(target))
+ u = qobject_cast<CoreIrcUser*>(newIrcUser(target));
+ if (u) {
+ u->setEncrypted(u->cipher()->setKey(key));
+ return;
+ }
+ }
#endif /* HAVE_QCA2 */
bool CoreNetwork::setAutoWhoDone(const QString &channel)
/***************************************************************************
- * Copyright (C) 2005-2012 by the Quassel Project *
+ * Copyright (C) 2005-2013 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
// Blowfish stuff
#ifdef HAVE_QCA2
- Cipher *cipher(const QString &recipient) const;
+ Cipher *cipher(const QString &recipient);
QByteArray cipherKey(const QString &recipient) const;
void setCipherKey(const QString &recipient, const QByteArray &key);
#endif
/***************************************************************************
- * Copyright (C) 2005-2012 by the Quassel Project *
+ * Copyright (C) 2005-2013 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
#include "netsplit.h"
#include "quassel.h"
+ #ifdef HAVE_QCA2
+ # include "keyevent.h"
+ #endif
+
CoreSessionEventProcessor::CoreSessionEventProcessor(CoreSession *session)
: BasicHandler("handleCtcp", session),
_coreSession(session)
CoreNetwork *net = coreNetwork(e);
- QString construct = net->saslAccount();
- construct.append(QChar(QChar::Null));
- construct.append(net->saslAccount());
- construct.append(QChar(QChar::Null));
- construct.append(net->saslPassword());
- QByteArray saslData = QByteArray(construct.toAscii().toBase64());
- saslData.prepend("AUTHENTICATE ");
- net->putRawLine(saslData);
+#ifdef HAVE_SSL
+ if (net->identityPtr()->sslCert().isNull()) {
+#endif
+ QString construct = net->saslAccount();
+ construct.append(QChar(QChar::Null));
+ construct.append(net->saslAccount());
+ construct.append(QChar(QChar::Null));
+ construct.append(net->saslPassword());
+ QByteArray saslData = QByteArray(construct.toAscii().toBase64());
+ saslData.prepend("AUTHENTICATE ");
+ net->putRawLine(saslData);
+#ifdef HAVE_SSL
+ } else {
+ net->putRawLine("AUTHENTICATE +");
+ }
+#endif
}
// additional CAP messages (ls, multi-prefix, et cetera).
if (e->params().count() == 3) {
- if (e->params().at(2) == "sasl") {
+ if (e->params().at(2).startsWith("sasl")) { // Freenode (at least) sends "sasl " with a trailing space for some reason!
// FIXME use event
- coreNetwork(e)->putRawLine(coreNetwork(e)->serverEncode("AUTHENTICATE PLAIN")); // Only working with PLAIN atm, blowfish later
+ // if the current identity has a cert set, use SASL EXTERNAL
+#ifdef HAVE_SSL
+ if (!coreNetwork(e)->identityPtr()->sslCert().isNull()) {
+ coreNetwork(e)->putRawLine(coreNetwork(e)->serverEncode("AUTHENTICATE EXTERNAL"));
+ } else {
+#endif
+ // Only working with PLAIN atm, blowfish later
+ coreNetwork(e)->putRawLine(coreNetwork(e)->serverEncode("AUTHENTICATE PLAIN"));
+#ifdef HAVE_SSL
+ }
+#endif
}
}
}
}
+ #ifdef HAVE_QCA2
+ void CoreSessionEventProcessor::processKeyEvent(KeyEvent *e)
+ {
+ if (!Cipher::neededFeaturesAvailable()) {
+ emit newEvent(new MessageEvent(Message::Error, e->network(), tr("Unable to perform key exchange."), e->prefix(), e->target(), Message::None, e->timestamp()));
+ return;
+ }
+ CoreNetwork *net = qobject_cast<CoreNetwork*>(e->network());
+ Cipher *c = net->cipher(e->target());
+ if (!c) // happens when there is no CoreIrcChannel for the target (i.e. never?)
+ return;
+
+ if (e->exchangeType() == KeyEvent::Init) {
+ QByteArray pubKey = c->parseInitKeyX(e->key());
+ if (pubKey.isEmpty()) {
+ emit newEvent(new MessageEvent(Message::Error, e->network(), tr("Unable to parse the DH1080_INIT. Key exchange failed."), e->prefix(), e->target(), Message::None, e->timestamp()));
+ return;
+ } else {
+ net->setCipherKey(e->target(), c->key());
+ emit newEvent(new MessageEvent(Message::Info, e->network(), tr("Your key is set and messages will be encrypted."), e->prefix(), e->target(), Message::None, e->timestamp()));
+ QList<QByteArray> p;
+ p << net->serverEncode(e->target()) << net->serverEncode("DH1080_FINISH ")+pubKey;
+ net->putCmd("NOTICE", p);
+ }
+ } else {
+ if (c->parseFinishKeyX(e->key())) {
+ net->setCipherKey(e->target(), c->key());
+ emit newEvent(new MessageEvent(Message::Info, e->network(), tr("Your key is set and messages will be encrypted."), e->prefix(), e->target(), Message::None, e->timestamp()));
+ } else {
+ emit newEvent(new MessageEvent(Message::Info, e->network(), tr("Failed to parse DH1080_FINISH. Key exchange failed."), e->prefix(), e->target(), Message::None, e->timestamp()));
+ }
+ }
+ }
+ #endif
+
+
/* RPL_WELCOME */
void CoreSessionEventProcessor::processIrcEvent001(IrcEvent *e)
{
/***************************************************************************
- * Copyright (C) 2005-2012 by the Quassel Project *
+ * Copyright (C) 2005-2013 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
class IrcEventNumeric;
class Netsplit;
+ #ifdef HAVE_QCA2
+ class KeyEvent;
+ #endif
+
class CoreSessionEventProcessor : public BasicHandler
{
Q_OBJECT
Q_INVOKABLE void processIrcEventQuit(IrcEvent *event);
Q_INVOKABLE void lateProcessIrcEventQuit(IrcEvent *event);
Q_INVOKABLE void processIrcEventTopic(IrcEvent *event);
+ #ifdef HAVE_QCA2
+ Q_INVOKABLE void processKeyEvent(KeyEvent *event);
+ #endif
Q_INVOKABLE void processIrcEvent001(IrcEvent *event); // RPL_WELCOME
Q_INVOKABLE void processIrcEvent005(IrcEvent *event); // RPL_ISUPPORT
/***************************************************************************
- * Copyright (C) 2005-2012 by the Quassel Project *
+ * Copyright (C) 2005-2013 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
}
network()->setCipherKey(target, QByteArray());
-
- if (network()->isChannelName(target) && network()->channels().contains(target)) {
- qobject_cast<CoreIrcChannel *>(network()->ircChannel(target))->setEncrypted(false);
- }
- else if (network()->nicks().contains(target)) {
- qobject_cast<CoreIrcUser *>(network()->ircUser(target))->setEncrypted(false);
- }
-
emit displayMsg(Message::Info, bufferInfo.bufferName(), tr("The key for %1 has been deleted.").arg(target));
#else
}
+ void CoreUserInputHandler::handleKeyx(const BufferInfo &bufferInfo, const QString &msg)
+ {
+ #ifdef HAVE_QCA2
+ if (!bufferInfo.isValid())
+ return;
+
+ if (!Cipher::neededFeaturesAvailable())
+ return;
+
+ QStringList parms = msg.split(' ', QString::SkipEmptyParts);
+
+ if (parms.count() == 0 && !bufferInfo.bufferName().isEmpty())
+ parms.prepend(bufferInfo.bufferName());
+ else if (parms.count() != 1) {
+ emit displayMsg(Message::Info, bufferInfo.bufferName(),
+ tr("[usage] /keyx [<nick|channel>] Initiates a DH1080 key exchange with the target."));
+ return;
+ }
+
+ QString target = parms.at(0);
+
+ Cipher *cipher = network()->cipher(target);
+ if (!cipher) // happens when there is no CoreIrcChannel for the target
+ return;
+
+ QByteArray pubKey = cipher->initKeyExchange();
+ if (pubKey.isEmpty())
+ emit displayMsg(Message::Error, bufferInfo.bufferName(), tr("Failed to initiate key exchange with %1.").arg(target));
+ else {
+ QList<QByteArray> params;
+ params << serverEncode(target) << serverEncode("DH1080_INIT ") + pubKey;
+ emit putCmd("NOTICE", params);
+ emit displayMsg(Message::Info, bufferInfo.bufferName(), tr("Initiated key exchange with %1.").arg(target));
+ }
+ #else
+ Q_UNUSED(msg)
+ emit displayMsg(Message::Error, bufferInfo.bufferName(), tr("Error: Setting an encryption key requires Quassel to have been built "
+ "with support for the Qt Cryptographic Architecture (QCA) library. "
+ "Contact your distributor about a Quassel package with QCA "
+ "support, or rebuild Quassel with QCA present."));
+ #endif
+ }
+
+
void CoreUserInputHandler::handleKick(const BufferInfo &bufferInfo, const QString &msg)
{
QString nick = msg.section(' ', 0, 0, QString::SectionSkipEmpty);
QString target = parms.at(0);
QByteArray key = parms.at(1).toLocal8Bit();
-
network()->setCipherKey(target, key);
- if (network()->isChannelName(target) && network()->channels().contains(target))
- qobject_cast<CoreIrcChannel *>(network()->ircChannel(target))->setEncrypted(true);
- else if (network()->nicks().contains(target))
- qobject_cast<CoreIrcUser *>(network()->ircUser(target))->setEncrypted(true);
-
emit displayMsg(Message::Info, bufferInfo.bufferName(), tr("The key for %1 has been set.").arg(target));
#else
Q_UNUSED(msg)
QByteArray crypted = message.left(splitPos);
bool isEncrypted = false;
#ifdef HAVE_QCA2
- if (cipher && !message.isEmpty()) {
+ if (cipher && !cipher->key().isEmpty() && !message.isEmpty()) {
isEncrypted = cipher->encrypt(crypted);
}
#endif
return message_;
Cipher *cipher = network()->cipher(target);
- if (!cipher)
+ if (!cipher || cipher->key().isEmpty())
return message_;
QByteArray message = message_;
/***************************************************************************
- * Copyright (C) 2005-2012 by the Quassel Project *
+ * Copyright (C) 2005-2013 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
void handleDevoice(const BufferInfo &bufferInfo, const QString &text);
void handleInvite(const BufferInfo &bufferInfo, const QString &text);
void handleJoin(const BufferInfo &bufferInfo, const QString &text);
+ void handleKeyx(const BufferInfo &bufferInfo, const QString &text);
void handleKick(const BufferInfo &bufferInfo, const QString &text);
void handleKill(const BufferInfo &bufferInfo, const QString &text);
void handleList(const BufferInfo &bufferInfo, const QString &text);
/***************************************************************************
- * Copyright (C) 2005-2012 by the Quassel Project *
+ * Copyright (C) 2005-2013 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
#ifdef HAVE_QCA2
# include "cipher.h"
+ # include "keyevent.h"
#endif
IrcParser::IrcParser(CoreSession *session) :
return message;
Cipher *cipher = qobject_cast<CoreNetwork *>(network)->cipher(bufferName);
- if (!cipher)
+ if (!cipher || cipher->key().isEmpty())
return message;
return isTopic ? cipher->decryptTopic(message) : cipher->decrypt(message);
if (!net->isChannelName(target))
target = nickFromMask(prefix);
}
- events << new IrcEventRawMessage(EventManager::IrcEventRawNotice, net, params[1], prefix, target, e->timestamp());
+
+ #ifdef HAVE_QCA2
+ // Handle DH1080 key exchange
+ if (params[1].startsWith("DH1080_INIT")) {
+ events << new KeyEvent(EventManager::KeyEvent, net, prefix, target, KeyEvent::Init, params[1].mid(12));
+ } else if (params[1].startsWith("DH1080_FINISH")) {
+ events << new KeyEvent(EventManager::KeyEvent, net, prefix, target, KeyEvent::Finish, params[1].mid(14));
+ } else
+ #endif
+ events << new IrcEventRawMessage(EventManager::IrcEventRawNotice, net, params[1], prefix, target, e->timestamp());
}
}
break;