-INSERT INTO buffer (bufferid, userid, groupid, networkid, buffername, buffercname, buffertype, lastmsgid, lastseenmsgid, markerlinemsgid, bufferactivity, key, joined)
-VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+INSERT INTO buffer (bufferid, userid, groupid, networkid, buffername, buffercname, buffertype, lastmsgid, lastseenmsgid, markerlinemsgid, bufferactivity, key, joined, cipher)
+VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
--- /dev/null
+SELECT buffername, cipher
+FROM buffer
+WHERE userid = :userid AND networkid = :networkid AND buffertype IN (2, 4)
bufferactivity integer NOT NULL DEFAULT 0,
key varchar(128),
joined boolean NOT NULL DEFAULT FALSE, -- BOOL
+ cipher TEXT,
UNIQUE(userid, networkid, buffercname),
CHECK (buffer.lastseenmsgid <= buffer.lastmsgid)
)
--- /dev/null
+UPDATE buffer
+SET cipher = :cipher
+WHERE userid = :userid AND networkid = :networkid AND buffercname = :buffercname
--- /dev/null
+ALTER TABLE buffer
+ADD COLUMN cipher TEXT
-SELECT bufferid, userid, groupid, networkid, buffername, buffercname, buffertype, lastmsgid, lastseenmsgid, markerlinemsgid, bufferactivity, key, joined
+SELECT bufferid, userid, groupid, networkid, buffername, buffercname, buffertype, lastmsgid, lastseenmsgid, markerlinemsgid, bufferactivity, key, joined, cipher
FROM buffer
--- /dev/null
+SELECT buffername, cipher
+FROM buffer
+WHERE userid = :userid AND networkid = :networkid AND buffertype IN (2, 4)
bufferactivity INTEGER NOT NULL DEFAULT 0,
key TEXT,
joined INTEGER NOT NULL DEFAULT 0, -- BOOL
+ cipher TEXT,
CHECK (lastseenmsgid <= lastmsgid)
)
--- /dev/null
+UPDATE buffer
+SET cipher = :cipher
+WHERE userid = :userid AND networkid = :networkid AND buffercname = :buffercname
--- /dev/null
+ALTER TABLE buffer
+ADD COLUMN cipher TEXT
int bufferactivity;
QString key;
bool joined;
+ QString cipher;
};
struct BacklogMO {
}
+ //! Get a hash of buffers with their ciphers for a given network
+ /** The keys are channel names and values are ciphers (possibly empty)
+ * \note This method is threadsafe
+ *
+ * \param user The id of the networks owner
+ * \param networkId The Id of the network
+ */
+ static inline QHash<QString, QByteArray> bufferCiphers(UserId user, const NetworkId &networkId)
+ {
+ return instance()->_storage->bufferCiphers(user, networkId);
+ }
+
+
+ //! Update the cipher of a buffer
+ /** \note This method is threadsafe
+ *
+ * \param user The Id of the networks owner
+ * \param networkId The Id of the network
+ * \param bufferName The Cname of the buffer
+ * \param cipher The cipher for the buffer
+ */
+ static inline void setBufferCipher(UserId user, const NetworkId &networkId, const QString &bufferName, const QByteArray &cipher)
+ {
+ return instance()->_storage->setBufferCipher(user, networkId, bufferName, cipher);
+ }
+
+
//! Update the key of a channel
/** \note This method is threadsafe
*
***************************************************************************/
#include "coreircuser.h"
+#include "corenetwork.h"
CoreIrcUser::CoreIrcUser(const QString &hostmask, Network *network) : IrcUser(hostmask, network)
{
#ifdef HAVE_QCA2
_cipher = 0;
+
+ // Get the cipher key from CoreNetwork if present
+ CoreNetwork *coreNetwork = qobject_cast<CoreNetwork *>(network);
+ if (coreNetwork) {
+ QByteArray key = coreNetwork->readChannelCipherKey(nick().toLower());
+ if (!key.isEmpty()) {
+ if (!_cipher) {
+ _cipher = new Cipher();
+ }
+ setEncrypted(_cipher->setKey(key));
+ }
+ }
#endif
}
CoreIrcUser::~CoreIrcUser()
{
#ifdef HAVE_QCA2
+ // Store the cipher key in CoreNetwork, including empty keys if a cipher
+ // exists. There is no need to store the empty key if no cipher exists; no
+ // key was present when instantiating and no key was set during the
+ // channel's lifetime.
+ CoreNetwork *coreNetwork = qobject_cast<CoreNetwork *>(network());
+ if (coreNetwork && _cipher) {
+ coreNetwork->storeChannelCipherKey(nick().toLower(), _cipher->key());
+ }
+
delete _cipher;
#endif
}
_channelKeys[chan.toLower()] = channels[chan];
}
+ QHash<QString, QByteArray> bufferCiphers = coreSession()->bufferCiphers(networkId());
+ foreach(QString buffer, bufferCiphers.keys()) {
+ storeChannelCipherKey(buffer.toLower(), bufferCiphers[buffer]);
+ }
+
connect(networkConfig(), SIGNAL(pingTimeoutEnabledSet(bool)), SLOT(enablePingTimeout(bool)));
connect(networkConfig(), SIGNAL(pingIntervalSet(int)), SLOT(setPingInterval(int)));
connect(networkConfig(), SIGNAL(autoWhoEnabledSet(bool)), SLOT(setAutoWhoEnabled(bool)));
CoreIrcChannel *c = qobject_cast<CoreIrcChannel*>(ircChannel(target));
if (c) {
c->setEncrypted(c->cipher()->setKey(key));
+ coreSession()->setBufferCipher(networkId(), target, key);
return;
}
if (u) {
u->setEncrypted(u->cipher()->setKey(key));
+ coreSession()->setBufferCipher(networkId(), target, key);
return;
}
}
}
+QHash<QString, QByteArray> CoreSession::bufferCiphers(NetworkId id) const
+{
+ return Core::bufferCiphers(user(), id);
+}
+
+void CoreSession::setBufferCipher(NetworkId id, const QString &bufferName, const QByteArray &cipher) const
+{
+ Core::setBufferCipher(user(), id, bufferName, cipher);
+}
+
+
// FIXME switch to BufferId
void CoreSession::msgFromClient(BufferInfo bufinfo, QString msg)
{
QHash<QString, QString> persistentChannels(NetworkId) const;
+ QHash<QString, QByteArray> bufferCiphers(NetworkId id) const;
+ void setBufferCipher(NetworkId id, const QString &bufferName, const QByteArray &cipher) const;
+
/**
* Marks us away (or unaway) on all networks
*
return result;
}
+QHash<QString, QByteArray> PostgreSqlStorage::bufferCiphers(UserId user, const NetworkId &networkId)
+{
+ QHash<QString, QByteArray> bufferCiphers;
+
+ QSqlDatabase db = logDb();
+ if (!beginReadOnlyTransaction(db)) {
+ qWarning() << "PostgreSqlStorage::persistentChannels(): cannot start read only transaction!";
+ qWarning() << " -" << qPrintable(db.lastError().text());
+ return bufferCiphers;
+ }
+
+ QSqlQuery query(db);
+ query.prepare(queryString("select_buffer_ciphers"));
+ query.bindValue(":userid", user.toInt());
+ query.bindValue(":networkid", networkId.toInt());
+ safeExec(query);
+ watchQuery(query);
+
+ while (query.next()) {
+ bufferCiphers[query.value(0).toString()] = QByteArray::fromHex(query.value(1).toString().toUtf8());
+ }
+
+ db.commit();
+ return bufferCiphers;
+}
+
+void PostgreSqlStorage::setBufferCipher(UserId user, const NetworkId &networkId, const QString &bufferName, const QByteArray &cipher)
+{
+ QSqlQuery query(logDb());
+ query.prepare(queryString("update_buffer_cipher"));
+ query.bindValue(":userid", user.toInt());
+ query.bindValue(":networkid", networkId.toInt());
+ query.bindValue(":buffercname", bufferName.toLower());
+ query.bindValue(":cipher", QString(cipher.toHex()));
+ safeExec(query);
+ watchQuery(query);
+}
+
bool PostgreSqlStorage::logMessage(Message &msg)
{
QSqlDatabase db = logDb();
bindValue(10, buffer.bufferactivity);
bindValue(11, buffer.key);
bindValue(12, buffer.joined);
+ bindValue(13, buffer.cipher);
return exec();
}
void setBufferActivity(UserId id, BufferId bufferId, Message::Types type) override;
QHash<BufferId, Message::Types> bufferActivities(UserId id) override;
Message::Types bufferActivity(BufferId bufferId, MsgId lastSeenMsgId) override;
+ QHash<QString, QByteArray> bufferCiphers(UserId user, const NetworkId &networkId) override;
+ void setBufferCipher(UserId user, const NetworkId &networkId, const QString &bufferName, const QByteArray &cipher) override;
/* Message handling */
bool logMessage(Message &msg) override;
<file>./SQL/PostgreSQL/select_buffer_bufferactivities.sql</file>
<file>./SQL/PostgreSQL/select_buffer_bufferactivity.sql</file>
<file>./SQL/PostgreSQL/select_buffer_by_id.sql</file>
+ <file>./SQL/PostgreSQL/select_buffer_ciphers.sql</file>
<file>./SQL/PostgreSQL/select_buffer_lastseen_messages.sql</file>
<file>./SQL/PostgreSQL/select_buffer_markerlinemsgids.sql</file>
<file>./SQL/PostgreSQL/select_buffers.sql</file>
<file>./SQL/PostgreSQL/setup_130_function_lastmsgid.sql</file>
<file>./SQL/PostgreSQL/update_backlog_bufferid.sql</file>
<file>./SQL/PostgreSQL/update_buffer_bufferactivity.sql</file>
+ <file>./SQL/PostgreSQL/update_buffer_cipher.sql</file>
<file>./SQL/PostgreSQL/update_buffer_lastseen.sql</file>
<file>./SQL/PostgreSQL/update_buffer_markerlinemsgid.sql</file>
<file>./SQL/PostgreSQL/update_buffer_name.sql</file>
<file>./SQL/PostgreSQL/version/22/upgrade_000_alter_quasseluser_add_authenticator.sql</file>
<file>./SQL/PostgreSQL/version/23/upgrade_000_create_senderprefixes.sql</file>
<file>./SQL/PostgreSQL/version/24/upgrade_000_alter_buffer_add_bufferactivity.sql</file>
+ <file>./SQL/PostgreSQL/version/25/upgrade_000_alter_buffer_add_cipher.sql</file>
<file>./SQL/SQLite/delete_backlog_by_uid.sql</file>
<file>./SQL/SQLite/delete_backlog_for_buffer.sql</file>
<file>./SQL/SQLite/delete_backlog_for_network.sql</file>
<file>./SQL/SQLite/select_buffer_bufferactivities.sql</file>
<file>./SQL/SQLite/select_buffer_bufferactivity.sql</file>
<file>./SQL/SQLite/select_buffer_by_id.sql</file>
+ <file>./SQL/SQLite/select_buffer_ciphers.sql</file>
<file>./SQL/SQLite/select_buffer_lastseen_messages.sql</file>
<file>./SQL/SQLite/select_buffer_markerlinemsgids.sql</file>
<file>./SQL/SQLite/select_buffers.sql</file>
<file>./SQL/SQLite/setup_140_identity_nick.sql</file>
<file>./SQL/SQLite/update_backlog_bufferid.sql</file>
<file>./SQL/SQLite/update_buffer_bufferactivity.sql</file>
+ <file>./SQL/SQLite/update_buffer_cipher.sql</file>
<file>./SQL/SQLite/update_buffer_lastseen.sql</file>
<file>./SQL/SQLite/update_buffer_markerlinemsgid.sql</file>
<file>./SQL/SQLite/update_buffer_name.sql</file>
<file>./SQL/SQLite/version/24/upgrade_000_create_senderprefixes.sql</file>
<file>./SQL/SQLite/version/25/upgrade_000_alter_buffer_add_bufferactivity.sql</file>
<file>./SQL/SQLite/version/26/upgrade_000_create_buffer_idx.sql</file>
+ <file>./SQL/SQLite/version/27/upgrade_000_alter_buffer_add_cipher.sql</file>
</qresource>
</RCC>
return result;
}
+QHash<QString, QByteArray> SqliteStorage::bufferCiphers(UserId user, const NetworkId &networkId)
+{
+ QHash<QString, QByteArray> bufferCiphers;
+
+ QSqlDatabase db = logDb();
+ db.transaction();
+ {
+ QSqlQuery query(db);
+ query.prepare(queryString("select_buffer_ciphers"));
+ query.bindValue(":userid", user.toInt());
+ query.bindValue(":networkid", networkId.toInt());
+
+ lockForRead();
+ safeExec(query);
+ watchQuery(query);
+ while (query.next()) {
+ bufferCiphers[query.value(0).toString()] = QByteArray::fromHex(query.value(1).toString().toUtf8());
+ }
+ }
+ unlock();
+ return bufferCiphers;
+}
+
+void SqliteStorage::setBufferCipher(UserId user, const NetworkId &networkId, const QString &bufferName, const QByteArray &cipher)
+{
+ QSqlDatabase db = logDb();
+ db.transaction();
+
+ {
+ QSqlQuery query(db);
+ query.prepare(queryString("update_buffer_cipher"));
+ query.bindValue(":userid", user.toInt());
+ query.bindValue(":networkid", networkId.toInt());
+ query.bindValue(":buffercname", bufferName.toLower());
+ query.bindValue(":cipher", QString(cipher.toHex()));
+
+ lockForWrite();
+ safeExec(query);
+ watchQuery(query);
+ db.commit();
+ }
+ unlock();
+}
+
bool SqliteStorage::logMessage(Message &msg)
{
QSqlDatabase db = logDb();
buffer.bufferactivity = value(10).toInt();
buffer.key = value(11).toString();
buffer.joined = value(12).toInt() == 1 ? true : false;
+ buffer.cipher = value(13).toString();
return true;
}
void setBufferActivity(UserId id, BufferId bufferId, Message::Types type) override;
QHash<BufferId, Message::Types> bufferActivities(UserId id) override;
Message::Types bufferActivity(BufferId bufferId, MsgId lastSeenMsgId) override;
+ QHash<QString, QByteArray> bufferCiphers(UserId user, const NetworkId &networkId) override;
+ void setBufferCipher(UserId user, const NetworkId &networkId, const QString &bufferName, const QByteArray &cipher) override;
/* Message handling */
bool logMessage(Message &msg) override;
*/
virtual Message::Types bufferActivity(BufferId bufferId, MsgId lastSeenMsgId) = 0;
+ //! Get a hash of buffers with their ciphers for a given network
+ /** The keys are channel names and values are ciphers (possibly empty)
+ * \note This method is threadsafe
+ *
+ * \param user The id of the networks owner
+ * \param networkId The Id of the network
+ */
+ virtual QHash<QString, QByteArray> bufferCiphers(UserId user, const NetworkId &networkId) = 0;
+
+ //! Update the cipher of a buffer
+ /** \note This method is threadsafe
+ *
+ * \param user The Id of the networks owner
+ * \param networkId The Id of the network
+ * \param bufferName The Cname of the buffer
+ * \param cipher The cipher for the buffer
+ */
+ virtual void setBufferCipher(UserId user, const NetworkId &networkId, const QString &bufferName, const QByteArray &cipher) = 0;
+
/* Message handling */
//! Store a Message in the storage backend and set its unique Id.