forked from blue/squawk
pasword storing options: jammed an alwaysAsk, external lib for password jamming, changelog
This commit is contained in:
parent
95f0d4008a
commit
7ce27d1c11
74
CHANGELOG.md
Normal file
74
CHANGELOG.md
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## Squawk 0.1.4 (UNRELEASED)
|
||||||
|
------------------------------
|
||||||
|
### New features
|
||||||
|
- several ways to manage your account password:
|
||||||
|
- store it in plain text with the config (like it always was)
|
||||||
|
- store it in config jammed (local hashing with the constant seed, not secure at all but might look like it is)
|
||||||
|
- ask the account password on each program launch
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
- never updating MUC avatars now update
|
||||||
|
- going offline related segfault fix
|
||||||
|
|
||||||
|
|
||||||
|
## Squawk 0.1.3 (Mar 31, 2020)
|
||||||
|
------------------------------
|
||||||
|
### New features
|
||||||
|
- delivery states for the messages
|
||||||
|
- delivery receipts now work for real
|
||||||
|
- avatars in conferences
|
||||||
|
- edited messages now display correctly
|
||||||
|
- restyling to get better look with different desktop themes
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
- clickable links now detects better
|
||||||
|
- fixed lost messages that came with no ID
|
||||||
|
- avatar related fixes
|
||||||
|
- message carbons now get turned on only if the server supports them
|
||||||
|
- progress spinner fix
|
||||||
|
- files in dialog now have better comment
|
||||||
|
|
||||||
|
|
||||||
|
## Squawk 0.1.2 (Dec 25, 2019)
|
||||||
|
------------------------------
|
||||||
|
### New features
|
||||||
|
- icons in roster for conferences
|
||||||
|
- pal avatar in dialog window
|
||||||
|
- avatars next to every message in dialog windows (not in conferences yet)
|
||||||
|
- roster window position and size now are stored in config
|
||||||
|
- expanded accounts and groups are stored in config
|
||||||
|
- availability (from top combobox) now is stored in config
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
- segfault when sending more then one attached file
|
||||||
|
- wrong path and name of saving file
|
||||||
|
- wrong message syntax when attaching file and writing text in the save message
|
||||||
|
- problem with links highlighting in dialog
|
||||||
|
- project building fixes
|
||||||
|
|
||||||
|
|
||||||
|
## Squawk 0.1.1 (Nov 16, 2019)
|
||||||
|
------------------------------
|
||||||
|
A lot of bug fixes, memory leaks fixes
|
||||||
|
### New features
|
||||||
|
- exchange files via HTTP File Upload
|
||||||
|
- download VCards of your contacts
|
||||||
|
- upload your VCard with information about your contact phones email addresses, names, career information and avatar
|
||||||
|
- avatars of your contacts in roster and in notifications
|
||||||
|
|
||||||
|
|
||||||
|
## Squawk 0.0.5 (Oct 10, 2019)
|
||||||
|
------------------------------
|
||||||
|
### Features
|
||||||
|
- chat directly
|
||||||
|
- have multiple accounts
|
||||||
|
- add contacts
|
||||||
|
- remove contacts
|
||||||
|
- assign contact to different groups
|
||||||
|
- chat in MUCs
|
||||||
|
- join MUCs, leave them, keep them subscribed or unsubscribed
|
||||||
|
- download attachmets
|
||||||
|
- local history
|
||||||
|
- desktop notifications of new messages
|
@ -74,6 +74,8 @@ endif()
|
|||||||
add_subdirectory(ui)
|
add_subdirectory(ui)
|
||||||
add_subdirectory(core)
|
add_subdirectory(core)
|
||||||
|
|
||||||
|
add_subdirectory(external/simpleCrypt)
|
||||||
|
|
||||||
target_link_libraries(squawk squawkUI)
|
target_link_libraries(squawk squawkUI)
|
||||||
target_link_libraries(squawk squawkCORE)
|
target_link_libraries(squawk squawkCORE)
|
||||||
target_link_libraries(squawk uuid)
|
target_link_libraries(squawk uuid)
|
||||||
|
@ -37,3 +37,4 @@ target_link_libraries(squawkCORE Qt5::Gui)
|
|||||||
target_link_libraries(squawkCORE Qt5::Xml)
|
target_link_libraries(squawkCORE Qt5::Xml)
|
||||||
target_link_libraries(squawkCORE qxmpp)
|
target_link_libraries(squawkCORE qxmpp)
|
||||||
target_link_libraries(squawkCORE lmdb)
|
target_link_libraries(squawkCORE lmdb)
|
||||||
|
target_link_libraries(squawkCORE simpleCrypt)
|
||||||
|
@ -52,14 +52,31 @@ void Core::Squawk::stop()
|
|||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.beginGroup("core");
|
settings.beginGroup("core");
|
||||||
settings.beginWriteArray("accounts");
|
settings.beginWriteArray("accounts");
|
||||||
|
SimpleCrypt crypto(passwordHash);
|
||||||
for (std::deque<Account*>::size_type i = 0; i < accounts.size(); ++i) {
|
for (std::deque<Account*>::size_type i = 0; i < accounts.size(); ++i) {
|
||||||
settings.setArrayIndex(i);
|
settings.setArrayIndex(i);
|
||||||
Account* acc = accounts[i];
|
Account* acc = accounts[i];
|
||||||
|
|
||||||
|
Shared::AccountPassword ap = acc->getPasswordType();
|
||||||
|
QString password;
|
||||||
|
|
||||||
|
switch (ap) {
|
||||||
|
case Shared::AccountPassword::plain:
|
||||||
|
password = acc->getPassword();
|
||||||
|
break;
|
||||||
|
case Shared::AccountPassword::jammed:
|
||||||
|
password = crypto.encryptToString(acc->getPassword());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
settings.setValue("name", acc->getName());
|
settings.setValue("name", acc->getName());
|
||||||
settings.setValue("server", acc->getServer());
|
settings.setValue("server", acc->getServer());
|
||||||
settings.setValue("login", acc->getLogin());
|
settings.setValue("login", acc->getLogin());
|
||||||
settings.setValue("password", acc->getPassword());
|
settings.setValue("password", password);
|
||||||
settings.setValue("resource", acc->getResource());
|
settings.setValue("resource", acc->getResource());
|
||||||
|
settings.setValue("passwordType", static_cast<int>(ap));
|
||||||
}
|
}
|
||||||
settings.endArray();
|
settings.endArray();
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
@ -318,12 +335,37 @@ void Core::Squawk::modifyAccountRequest(const QString& name, const QMap<QString,
|
|||||||
|
|
||||||
Core::Account* acc = itr->second;
|
Core::Account* acc = itr->second;
|
||||||
Shared::ConnectionState st = acc->getState();
|
Shared::ConnectionState st = acc->getState();
|
||||||
|
QMap<QString, QVariant>::const_iterator mItr;
|
||||||
|
bool needToReconnect = false;
|
||||||
|
|
||||||
if (st != Shared::ConnectionState::disconnected) {
|
mItr = map.find("login");
|
||||||
|
if (mItr != map.end()) {
|
||||||
|
needToReconnect = acc->getLogin() != mItr->toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!needToReconnect) {
|
||||||
|
mItr = map.find("password");
|
||||||
|
if (mItr != map.end()) {
|
||||||
|
needToReconnect = acc->getPassword() != mItr->toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!needToReconnect) {
|
||||||
|
mItr = map.find("server");
|
||||||
|
if (mItr != map.end()) {
|
||||||
|
needToReconnect = acc->getServer() != mItr->toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!needToReconnect) {
|
||||||
|
mItr = map.find("resource");
|
||||||
|
if (mItr != map.end()) {
|
||||||
|
needToReconnect = acc->getResource() != mItr->toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needToReconnect && st != Shared::ConnectionState::disconnected) {
|
||||||
acc->reconnect();
|
acc->reconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<QString, QVariant>::const_iterator mItr;
|
|
||||||
mItr = map.find("login");
|
mItr = map.find("login");
|
||||||
if (mItr != map.end()) {
|
if (mItr != map.end()) {
|
||||||
acc->setLogin(mItr->toString());
|
acc->setLogin(mItr->toString());
|
||||||
@ -344,6 +386,11 @@ void Core::Squawk::modifyAccountRequest(const QString& name, const QMap<QString,
|
|||||||
acc->setServer(mItr->toString());
|
acc->setServer(mItr->toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mItr = map.find("passwordType");
|
||||||
|
if (mItr != map.end()) {
|
||||||
|
acc->setPasswordType(Shared::Global::fromInt<Shared::AccountPassword>(mItr->toInt()));
|
||||||
|
}
|
||||||
|
|
||||||
emit changeAccount(name, map);
|
emit changeAccount(name, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -570,6 +617,17 @@ void Core::Squawk::uploadVCard(const QString& account, const Shared::VCard& card
|
|||||||
itr->second->uploadVCard(card);
|
itr->second->uploadVCard(card);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Core::Squawk::responsePassword(const QString& account, const QString& password)
|
||||||
|
{
|
||||||
|
AccountsMap::const_iterator itr = amap.find(account);
|
||||||
|
if (itr == amap.end()) {
|
||||||
|
qDebug() << "An attempt to set password to non existing account" << account << ", skipping";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
itr->second->setPassword(password);
|
||||||
|
accountReady();
|
||||||
|
}
|
||||||
|
|
||||||
void Core::Squawk::readSettings()
|
void Core::Squawk::readSettings()
|
||||||
{
|
{
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
@ -614,5 +672,16 @@ void Core::Squawk::parseAccount(
|
|||||||
addAccount(login, server, password, name, resource, passwordType);
|
addAccount(login, server, password, name, resource, passwordType);
|
||||||
accountReady();
|
accountReady();
|
||||||
break;
|
break;
|
||||||
|
case Shared::AccountPassword::jammed: {
|
||||||
|
SimpleCrypt crypto(passwordHash);
|
||||||
|
QString decrypted = crypto.decryptToString(password);
|
||||||
|
addAccount(login, server, decrypted, name, resource, passwordType);
|
||||||
|
accountReady();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Shared::AccountPassword::alwaysAsk:
|
||||||
|
addAccount(login, server, QString(), name, resource, passwordType);
|
||||||
|
emit requestPassword(name);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include "shared/message.h"
|
#include "shared/message.h"
|
||||||
#include "shared/global.h"
|
#include "shared/global.h"
|
||||||
#include "networkaccess.h"
|
#include "networkaccess.h"
|
||||||
|
#include "external/simpleCrypt/simplecrypt.h"
|
||||||
|
|
||||||
namespace Core
|
namespace Core
|
||||||
{
|
{
|
||||||
@ -73,6 +74,7 @@ signals:
|
|||||||
void uploadFileProgress(const QString& messageId, qreal value);
|
void uploadFileProgress(const QString& messageId, qreal value);
|
||||||
void responseVCard(const QString& jid, const Shared::VCard& card);
|
void responseVCard(const QString& jid, const Shared::VCard& card);
|
||||||
void changeMessage(const QString& account, const QString& jid, const QString& id, const QMap<QString, QVariant>& data);
|
void changeMessage(const QString& account, const QString& jid, const QString& id, const QMap<QString, QVariant>& data);
|
||||||
|
void requestPassword(const QString& account);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void start();
|
void start();
|
||||||
@ -101,6 +103,7 @@ public slots:
|
|||||||
void downloadFileRequest(const QString& messageId, const QString& url);
|
void downloadFileRequest(const QString& messageId, const QString& url);
|
||||||
void requestVCard(const QString& account, const QString& jid);
|
void requestVCard(const QString& account, const QString& jid);
|
||||||
void uploadVCard(const QString& account, const Shared::VCard& card);
|
void uploadVCard(const QString& account, const Shared::VCard& card);
|
||||||
|
void responsePassword(const QString& account, const QString& password);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::deque<Account*> Accounts;
|
typedef std::deque<Account*> Accounts;
|
||||||
@ -155,6 +158,8 @@ private:
|
|||||||
const QString& resource,
|
const QString& resource,
|
||||||
Shared::AccountPassword passwordType
|
Shared::AccountPassword passwordType
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static const quint64 passwordHash = 0x08d054225ac4871d;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
16
external/simpleCrypt/CMakeLists.txt
vendored
Normal file
16
external/simpleCrypt/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
project(simplecrypt)
|
||||||
|
|
||||||
|
set(CMAKE_AUTOMOC ON)
|
||||||
|
|
||||||
|
find_package(Qt5Core CONFIG REQUIRED)
|
||||||
|
|
||||||
|
set(simplecrypt_SRC
|
||||||
|
simplecrypt.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# Tell CMake to create the helloworld executable
|
||||||
|
add_library(simpleCrypt ${simplecrypt_SRC})
|
||||||
|
|
||||||
|
# Use the Widgets module from Qt 5.
|
||||||
|
target_link_libraries(simpleCrypt Qt5::Core)
|
252
external/simpleCrypt/simplecrypt.cpp
vendored
Normal file
252
external/simpleCrypt/simplecrypt.cpp
vendored
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2011, Andre Somers
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the Rathenau Instituut, Andre Somers nor the
|
||||||
|
names of its contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL ANDRE SOMERS BE LIABLE FOR ANY
|
||||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR #######; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#include "simplecrypt.h"
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QtDebug>
|
||||||
|
#include <QtGlobal>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
#include <QDataStream>
|
||||||
|
|
||||||
|
SimpleCrypt::SimpleCrypt():
|
||||||
|
m_key(0),
|
||||||
|
m_compressionMode(CompressionAuto),
|
||||||
|
m_protectionMode(ProtectionChecksum),
|
||||||
|
m_lastError(ErrorNoError)
|
||||||
|
{
|
||||||
|
qsrand(uint(QDateTime::currentMSecsSinceEpoch() & 0xFFFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
SimpleCrypt::SimpleCrypt(quint64 key):
|
||||||
|
m_key(key),
|
||||||
|
m_compressionMode(CompressionAuto),
|
||||||
|
m_protectionMode(ProtectionChecksum),
|
||||||
|
m_lastError(ErrorNoError)
|
||||||
|
{
|
||||||
|
qsrand(uint(QDateTime::currentMSecsSinceEpoch() & 0xFFFF));
|
||||||
|
splitKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleCrypt::setKey(quint64 key)
|
||||||
|
{
|
||||||
|
m_key = key;
|
||||||
|
splitKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimpleCrypt::splitKey()
|
||||||
|
{
|
||||||
|
m_keyParts.clear();
|
||||||
|
m_keyParts.resize(8);
|
||||||
|
for (int i=0;i<8;i++) {
|
||||||
|
quint64 part = m_key;
|
||||||
|
for (int j=i; j>0; j--)
|
||||||
|
part = part >> 8;
|
||||||
|
part = part & 0xff;
|
||||||
|
m_keyParts[i] = static_cast<char>(part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray SimpleCrypt::encryptToByteArray(const QString& plaintext)
|
||||||
|
{
|
||||||
|
QByteArray plaintextArray = plaintext.toUtf8();
|
||||||
|
return encryptToByteArray(plaintextArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray SimpleCrypt::encryptToByteArray(QByteArray plaintext)
|
||||||
|
{
|
||||||
|
if (m_keyParts.isEmpty()) {
|
||||||
|
qWarning() << "No key set.";
|
||||||
|
m_lastError = ErrorNoKeySet;
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QByteArray ba = plaintext;
|
||||||
|
|
||||||
|
CryptoFlags flags = CryptoFlagNone;
|
||||||
|
if (m_compressionMode == CompressionAlways) {
|
||||||
|
ba = qCompress(ba, 9); //maximum compression
|
||||||
|
flags |= CryptoFlagCompression;
|
||||||
|
} else if (m_compressionMode == CompressionAuto) {
|
||||||
|
QByteArray compressed = qCompress(ba, 9);
|
||||||
|
if (compressed.count() < ba.count()) {
|
||||||
|
ba = compressed;
|
||||||
|
flags |= CryptoFlagCompression;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray integrityProtection;
|
||||||
|
if (m_protectionMode == ProtectionChecksum) {
|
||||||
|
flags |= CryptoFlagChecksum;
|
||||||
|
QDataStream s(&integrityProtection, QIODevice::WriteOnly);
|
||||||
|
s << qChecksum(ba.constData(), ba.length());
|
||||||
|
} else if (m_protectionMode == ProtectionHash) {
|
||||||
|
flags |= CryptoFlagHash;
|
||||||
|
QCryptographicHash hash(QCryptographicHash::Sha1);
|
||||||
|
hash.addData(ba);
|
||||||
|
|
||||||
|
integrityProtection += hash.result();
|
||||||
|
}
|
||||||
|
|
||||||
|
//prepend a random char to the string
|
||||||
|
char randomChar = char(qrand() & 0xFF);
|
||||||
|
ba = randomChar + integrityProtection + ba;
|
||||||
|
|
||||||
|
int pos(0);
|
||||||
|
char lastChar(0);
|
||||||
|
|
||||||
|
int cnt = ba.count();
|
||||||
|
|
||||||
|
while (pos < cnt) {
|
||||||
|
ba[pos] = ba.at(pos) ^ m_keyParts.at(pos % 8) ^ lastChar;
|
||||||
|
lastChar = ba.at(pos);
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray resultArray;
|
||||||
|
resultArray.append(char(0x03)); //version for future updates to algorithm
|
||||||
|
resultArray.append(char(flags)); //encryption flags
|
||||||
|
resultArray.append(ba);
|
||||||
|
|
||||||
|
m_lastError = ErrorNoError;
|
||||||
|
return resultArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SimpleCrypt::encryptToString(const QString& plaintext)
|
||||||
|
{
|
||||||
|
QByteArray plaintextArray = plaintext.toUtf8();
|
||||||
|
QByteArray cypher = encryptToByteArray(plaintextArray);
|
||||||
|
QString cypherString = QString::fromLatin1(cypher.toBase64());
|
||||||
|
return cypherString;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SimpleCrypt::encryptToString(QByteArray plaintext)
|
||||||
|
{
|
||||||
|
QByteArray cypher = encryptToByteArray(plaintext);
|
||||||
|
QString cypherString = QString::fromLatin1(cypher.toBase64());
|
||||||
|
return cypherString;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SimpleCrypt::decryptToString(const QString &cyphertext)
|
||||||
|
{
|
||||||
|
QByteArray cyphertextArray = QByteArray::fromBase64(cyphertext.toLatin1());
|
||||||
|
QByteArray plaintextArray = decryptToByteArray(cyphertextArray);
|
||||||
|
QString plaintext = QString::fromUtf8(plaintextArray, plaintextArray.size());
|
||||||
|
|
||||||
|
return plaintext;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SimpleCrypt::decryptToString(QByteArray cypher)
|
||||||
|
{
|
||||||
|
QByteArray ba = decryptToByteArray(cypher);
|
||||||
|
QString plaintext = QString::fromUtf8(ba, ba.size());
|
||||||
|
|
||||||
|
return plaintext;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray SimpleCrypt::decryptToByteArray(const QString& cyphertext)
|
||||||
|
{
|
||||||
|
QByteArray cyphertextArray = QByteArray::fromBase64(cyphertext.toLatin1());
|
||||||
|
QByteArray ba = decryptToByteArray(cyphertextArray);
|
||||||
|
|
||||||
|
return ba;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray SimpleCrypt::decryptToByteArray(QByteArray cypher)
|
||||||
|
{
|
||||||
|
if (m_keyParts.isEmpty()) {
|
||||||
|
qWarning() << "No key set.";
|
||||||
|
m_lastError = ErrorNoKeySet;
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray ba = cypher;
|
||||||
|
|
||||||
|
if( cypher.count() < 3 )
|
||||||
|
return QByteArray();
|
||||||
|
|
||||||
|
char version = ba.at(0);
|
||||||
|
|
||||||
|
if (version !=3) { //we only work with version 3
|
||||||
|
m_lastError = ErrorUnknownVersion;
|
||||||
|
qWarning() << "Invalid version or not a cyphertext.";
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
CryptoFlags flags = CryptoFlags(ba.at(1));
|
||||||
|
|
||||||
|
ba = ba.mid(2);
|
||||||
|
int pos(0);
|
||||||
|
int cnt(ba.count());
|
||||||
|
char lastChar = 0;
|
||||||
|
|
||||||
|
while (pos < cnt) {
|
||||||
|
char currentChar = ba[pos];
|
||||||
|
ba[pos] = ba.at(pos) ^ lastChar ^ m_keyParts.at(pos % 8);
|
||||||
|
lastChar = currentChar;
|
||||||
|
++pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
ba = ba.mid(1); //chop off the random number at the start
|
||||||
|
|
||||||
|
bool integrityOk(true);
|
||||||
|
if (flags.testFlag(CryptoFlagChecksum)) {
|
||||||
|
if (ba.length() < 2) {
|
||||||
|
m_lastError = ErrorIntegrityFailed;
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
quint16 storedChecksum;
|
||||||
|
{
|
||||||
|
QDataStream s(&ba, QIODevice::ReadOnly);
|
||||||
|
s >> storedChecksum;
|
||||||
|
}
|
||||||
|
ba = ba.mid(2);
|
||||||
|
quint16 checksum = qChecksum(ba.constData(), ba.length());
|
||||||
|
integrityOk = (checksum == storedChecksum);
|
||||||
|
} else if (flags.testFlag(CryptoFlagHash)) {
|
||||||
|
if (ba.length() < 20) {
|
||||||
|
m_lastError = ErrorIntegrityFailed;
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
QByteArray storedHash = ba.left(20);
|
||||||
|
ba = ba.mid(20);
|
||||||
|
QCryptographicHash hash(QCryptographicHash::Sha1);
|
||||||
|
hash.addData(ba);
|
||||||
|
integrityOk = (hash.result() == storedHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!integrityOk) {
|
||||||
|
m_lastError = ErrorIntegrityFailed;
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags.testFlag(CryptoFlagCompression))
|
||||||
|
ba = qUncompress(ba);
|
||||||
|
|
||||||
|
m_lastError = ErrorNoError;
|
||||||
|
return ba;
|
||||||
|
}
|
225
external/simpleCrypt/simplecrypt.h
vendored
Normal file
225
external/simpleCrypt/simplecrypt.h
vendored
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2011, Andre Somers
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of the Rathenau Instituut, Andre Somers nor the
|
||||||
|
names of its contributors may be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL ANDRE SOMERS BE LIABLE FOR ANY
|
||||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR #######; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SIMPLECRYPT_H
|
||||||
|
#define SIMPLECRYPT_H
|
||||||
|
#include <QString>
|
||||||
|
#include <QVector>
|
||||||
|
#include <QFlags>
|
||||||
|
|
||||||
|
/**
|
||||||
|
@ short Simple encrypt*ion and decryption of strings and byte arrays
|
||||||
|
|
||||||
|
This class provides a simple implementation of encryption and decryption
|
||||||
|
of strings and byte arrays.
|
||||||
|
|
||||||
|
@warning The encryption provided by this class is NOT strong encryption. It may
|
||||||
|
help to shield things from curious eyes, but it will NOT stand up to someone
|
||||||
|
determined to break the encryption. Don't say you were not warned.
|
||||||
|
|
||||||
|
The class uses a 64 bit key. Simply create an instance of the class, set the key,
|
||||||
|
and use the encryptToString() method to calculate an encrypted version of the input string.
|
||||||
|
To decrypt that string again, use an instance of SimpleCrypt initialized with
|
||||||
|
the same key, and call the decryptToString() method with the encrypted string. If the key
|
||||||
|
matches, the decrypted version of the string will be returned again.
|
||||||
|
|
||||||
|
If you do not provide a key, or if something else is wrong, the encryption and
|
||||||
|
decryption function will return an empty string or will return a string containing nonsense.
|
||||||
|
lastError() will return a value indicating if the method was succesful, and if not, why not.
|
||||||
|
|
||||||
|
SimpleCrypt is prepared for the case that the encryption and decryption
|
||||||
|
algorithm is changed in a later version, by prepending a version identifier to the cypertext.
|
||||||
|
*/
|
||||||
|
class SimpleCrypt
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
CompressionMode describes if compression will be applied to the data to be
|
||||||
|
encrypted.
|
||||||
|
*/
|
||||||
|
enum CompressionMode {
|
||||||
|
CompressionAuto, /*!< Only apply compression if that results in a shorter plaintext. */
|
||||||
|
CompressionAlways, /*!< Always apply compression. Note that for short inputs, a compression may result in longer data */
|
||||||
|
CompressionNever /*!< Never apply compression. */
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
IntegrityProtectionMode describes measures taken to make it possible to detect problems with the data
|
||||||
|
or wrong decryption keys.
|
||||||
|
|
||||||
|
Measures involve adding a checksum or a cryptograhpic hash to the data to be encrypted. This
|
||||||
|
increases the length of the resulting cypertext, but makes it possible to check if the plaintext
|
||||||
|
appears to be valid after decryption.
|
||||||
|
*/
|
||||||
|
enum IntegrityProtectionMode {
|
||||||
|
ProtectionNone, /*!< The integerity of the encrypted data is not protected. It is not really possible to detect a wrong key, for instance. */
|
||||||
|
ProtectionChecksum,/*!< A simple checksum is used to verify that the data is in order. If not, an empty string is returned. */
|
||||||
|
ProtectionHash /*!< A cryptographic hash is used to verify the integrity of the data. This method produces a much stronger, but longer check */
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
Error describes t*he type of error that occured.
|
||||||
|
*/
|
||||||
|
enum Error {
|
||||||
|
ErrorNoError, /*!< No error occurred. */
|
||||||
|
ErrorNoKeySet, /*!< No key was set. You can not encrypt or decrypt without a valid key. */
|
||||||
|
ErrorUnknownVersion, /*!< The version of this data is unknown, or the data is otherwise not valid. */
|
||||||
|
ErrorIntegrityFailed, /*!< The integrity check of the data failed. Perhaps the wrong key was used. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Constructor. *
|
||||||
|
|
||||||
|
Constructs a SimpleCrypt instance without a valid key set on it.
|
||||||
|
*/
|
||||||
|
SimpleCrypt();
|
||||||
|
/**
|
||||||
|
Constructor. *
|
||||||
|
|
||||||
|
Constructs a SimpleCrypt instance and initializes it with the given @arg key.
|
||||||
|
*/
|
||||||
|
explicit SimpleCrypt(quint64 key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
( Re-) initializes* the key with the given @arg key.
|
||||||
|
*/
|
||||||
|
void setKey(quint64 key);
|
||||||
|
/**
|
||||||
|
Returns true if SimpleCrypt has been initialized with a key.
|
||||||
|
*/
|
||||||
|
bool hasKey() const {return !m_keyParts.isEmpty();}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Sets the compress*ion mode to use when encrypting data. The default mode is Auto.
|
||||||
|
|
||||||
|
Note that decryption is not influenced by this mode, as the decryption recognizes
|
||||||
|
what mode was used when encrypting.
|
||||||
|
*/
|
||||||
|
void setCompressionMode(CompressionMode mode) {m_compressionMode = mode;}
|
||||||
|
/**
|
||||||
|
Returns the CompressionMode that is currently in use.
|
||||||
|
*/
|
||||||
|
CompressionMode compressionMode() const {return m_compressionMode;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Sets the integrity mode to use when encrypting data. The default mode is Checksum.
|
||||||
|
|
||||||
|
Note that decryption is not influenced by this mode, as the decryption recognizes
|
||||||
|
what mode was used when encrypting.
|
||||||
|
*/
|
||||||
|
void setIntegrityProtectionMode(IntegrityProtectionMode mode) {m_protectionMode = mode;}
|
||||||
|
/**
|
||||||
|
Returns the IntegrityProtectionMode that is currently in use.
|
||||||
|
*/
|
||||||
|
IntegrityProtectionMode integrityProtectionMode() const {return m_protectionMode;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the last *error that occurred.
|
||||||
|
*/
|
||||||
|
Error lastError() const {return m_lastError;}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Encrypts the @arg* plaintext string with the key the class was initialized with, and returns
|
||||||
|
a cyphertext the result. The result is a base64 encoded version of the binary array that is the
|
||||||
|
actual result of the string, so it can be stored easily in a text format.
|
||||||
|
*/
|
||||||
|
QString encryptToString(const QString& plaintext) ;
|
||||||
|
/**
|
||||||
|
Encrypts the @arg* plaintext QByteArray with the key the class was initialized with, and returns
|
||||||
|
a cyphertext the result. The result is a base64 encoded version of the binary array that is the
|
||||||
|
actual result of the encryption, so it can be stored easily in a text format.
|
||||||
|
*/
|
||||||
|
QString encryptToString(QByteArray plaintext) ;
|
||||||
|
/**
|
||||||
|
Encrypts the @arg* plaintext string with the key the class was initialized with, and returns
|
||||||
|
a binary cyphertext in a QByteArray the result.
|
||||||
|
|
||||||
|
This method returns a byte array, that is useable for storing a binary format. If you need
|
||||||
|
a string you can store in a text file, use encryptToString() instead.
|
||||||
|
*/
|
||||||
|
QByteArray encryptToByteArray(const QString& plaintext) ;
|
||||||
|
/**
|
||||||
|
Encrypts the @arg* plaintext QByteArray with the key the class was initialized with, and returns
|
||||||
|
a binary cyphertext in a QByteArray the result.
|
||||||
|
|
||||||
|
This method returns a byte array, that is useable for storing a binary format. If you need
|
||||||
|
a string you can store in a text file, use encryptToString() instead.
|
||||||
|
*/
|
||||||
|
QByteArray encryptToByteArray(QByteArray plaintext) ;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Decrypts a cypher*text string encrypted with this class with the set key back to the
|
||||||
|
plain text version.
|
||||||
|
|
||||||
|
If an error occured, such as non-matching keys between encryption and decryption,
|
||||||
|
an empty string or a string containing nonsense may be returned.
|
||||||
|
*/
|
||||||
|
QString decryptToString(const QString& cyphertext) ;
|
||||||
|
/**
|
||||||
|
Decrypts a cypher*text string encrypted with this class with the set key back to the
|
||||||
|
plain text version.
|
||||||
|
|
||||||
|
If an error occured, such as non-matching keys between encryption and decryption,
|
||||||
|
an empty string or a string containing nonsense may be returned.
|
||||||
|
*/
|
||||||
|
QByteArray decryptToByteArray(const QString& cyphertext) ;
|
||||||
|
/**
|
||||||
|
Decrypts a cypher*text binary encrypted with this class with the set key back to the
|
||||||
|
plain text version.
|
||||||
|
|
||||||
|
If an error occured, such as non-matching keys between encryption and decryption,
|
||||||
|
an empty string or a string containing nonsense may be returned.
|
||||||
|
*/
|
||||||
|
QString decryptToString(QByteArray cypher) ;
|
||||||
|
/**
|
||||||
|
Decrypts a cypher*text binary encrypted with this class with the set key back to the
|
||||||
|
plain text version.
|
||||||
|
|
||||||
|
If an error occured, such as non-matching keys between encryption and decryption,
|
||||||
|
an empty string or a string containing nonsense may be returned.
|
||||||
|
*/
|
||||||
|
QByteArray decryptToByteArray(QByteArray cypher) ;
|
||||||
|
|
||||||
|
//enum to describe options that have been used for the encryption. Currently only one, but
|
||||||
|
//that only leaves room for future extensions like adding a cryptographic hash...
|
||||||
|
enum CryptoFlag{CryptoFlagNone = 0,
|
||||||
|
CryptoFlagCompression = 0x01,
|
||||||
|
CryptoFlagChecksum = 0x02,
|
||||||
|
CryptoFlagHash = 0x04
|
||||||
|
};
|
||||||
|
Q_DECLARE_FLAGS(CryptoFlags, CryptoFlag);
|
||||||
|
private:
|
||||||
|
|
||||||
|
void splitKey();
|
||||||
|
|
||||||
|
quint64 m_key;
|
||||||
|
QVector<char> m_keyParts;
|
||||||
|
CompressionMode m_compressionMode;
|
||||||
|
IntegrityProtectionMode m_protectionMode;
|
||||||
|
Error m_lastError;
|
||||||
|
};
|
||||||
|
Q_DECLARE_OPERATORS_FOR_FLAGS(SimpleCrypt::CryptoFlags)
|
||||||
|
|
||||||
|
#endif // SimpleCrypt_H
|
2
main.cpp
2
main.cpp
@ -116,6 +116,7 @@ int main(int argc, char *argv[])
|
|||||||
QObject::connect(&w, &Squawk::renameContactRequest, squawk, &Core::Squawk::renameContactRequest);
|
QObject::connect(&w, &Squawk::renameContactRequest, squawk, &Core::Squawk::renameContactRequest);
|
||||||
QObject::connect(&w, &Squawk::requestVCard, squawk, &Core::Squawk::requestVCard);
|
QObject::connect(&w, &Squawk::requestVCard, squawk, &Core::Squawk::requestVCard);
|
||||||
QObject::connect(&w, &Squawk::uploadVCard, squawk, &Core::Squawk::uploadVCard);
|
QObject::connect(&w, &Squawk::uploadVCard, squawk, &Core::Squawk::uploadVCard);
|
||||||
|
QObject::connect(&w, &Squawk::responsePassword, squawk, &Core::Squawk::responsePassword);
|
||||||
|
|
||||||
QObject::connect(squawk, &Core::Squawk::newAccount, &w, &Squawk::newAccount);
|
QObject::connect(squawk, &Core::Squawk::newAccount, &w, &Squawk::newAccount);
|
||||||
QObject::connect(squawk, &Core::Squawk::addContact, &w, &Squawk::addContact);
|
QObject::connect(squawk, &Core::Squawk::addContact, &w, &Squawk::addContact);
|
||||||
@ -146,6 +147,7 @@ int main(int argc, char *argv[])
|
|||||||
QObject::connect(squawk, &Core::Squawk::uploadFileProgress, &w, &Squawk::fileProgress);
|
QObject::connect(squawk, &Core::Squawk::uploadFileProgress, &w, &Squawk::fileProgress);
|
||||||
QObject::connect(squawk, &Core::Squawk::uploadFileError, &w, &Squawk::fileError);
|
QObject::connect(squawk, &Core::Squawk::uploadFileError, &w, &Squawk::fileError);
|
||||||
QObject::connect(squawk, &Core::Squawk::responseVCard, &w, &Squawk::responseVCard);
|
QObject::connect(squawk, &Core::Squawk::responseVCard, &w, &Squawk::responseVCard);
|
||||||
|
QObject::connect(squawk, &Core::Squawk::requestPassword, &w, &Squawk::requestPassword);
|
||||||
QObject::connect(squawk, &Core::Squawk::ready, &w, &Squawk::readSettings);
|
QObject::connect(squawk, &Core::Squawk::ready, &w, &Squawk::readSettings);
|
||||||
|
|
||||||
coreThread->start();
|
coreThread->start();
|
||||||
|
@ -110,11 +110,11 @@ static const std::deque<QString> messageStateThemeIcons = {"state-offline", "sta
|
|||||||
enum class AccountPassword {
|
enum class AccountPassword {
|
||||||
plain,
|
plain,
|
||||||
jammed,
|
jammed,
|
||||||
kwallet,
|
alwaysAsk,
|
||||||
alwaysAsk
|
kwallet
|
||||||
};
|
};
|
||||||
Q_ENUM_NS(AccountPassword)
|
Q_ENUM_NS(AccountPassword)
|
||||||
static const AccountPassword AccountPasswordHighest = AccountPassword::alwaysAsk;
|
static const AccountPassword AccountPasswordHighest = AccountPassword::kwallet;
|
||||||
static const AccountPassword AccountPasswordLowest = AccountPassword::plain;
|
static const AccountPassword AccountPasswordLowest = AccountPassword::plain;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -69,8 +69,8 @@ Shared::Global::Global():
|
|||||||
accountPassword({
|
accountPassword({
|
||||||
tr("Plain"),
|
tr("Plain"),
|
||||||
tr("Jammed"),
|
tr("Jammed"),
|
||||||
tr("KWallet"),
|
tr("Always Ask"),
|
||||||
tr("Always Ask")
|
tr("KWallet")
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
if (instance != 0) {
|
if (instance != 0) {
|
||||||
|
@ -39,6 +39,10 @@ Models::Account::Account(const QMap<QString, QVariant>& data, Models::Item* pare
|
|||||||
if (aItr != data.end()) {
|
if (aItr != data.end()) {
|
||||||
setAvailability(aItr.value().toUInt());
|
setAvailability(aItr.value().toUInt());
|
||||||
}
|
}
|
||||||
|
QMap<QString, QVariant>::const_iterator pItr = data.find("passwordType");
|
||||||
|
if (pItr != data.end()) {
|
||||||
|
setPasswordType(pItr.value().toUInt());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Models::Account::~Account()
|
Models::Account::~Account()
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
#include "ui_squawk.h"
|
#include "ui_squawk.h"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QInputDialog>
|
|
||||||
|
|
||||||
Squawk::Squawk(QWidget *parent) :
|
Squawk::Squawk(QWidget *parent) :
|
||||||
QMainWindow(parent),
|
QMainWindow(parent),
|
||||||
@ -31,7 +30,9 @@ Squawk::Squawk(QWidget *parent) :
|
|||||||
contextMenu(new QMenu()),
|
contextMenu(new QMenu()),
|
||||||
dbus("org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", QDBusConnection::sessionBus()),
|
dbus("org.freedesktop.Notifications", "/org/freedesktop/Notifications", "org.freedesktop.Notifications", QDBusConnection::sessionBus()),
|
||||||
requestedFiles(),
|
requestedFiles(),
|
||||||
vCards()
|
vCards(),
|
||||||
|
requestedAccountsForPasswords(),
|
||||||
|
prompt(0)
|
||||||
{
|
{
|
||||||
m_ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
m_ui->roster->setModel(&rosterModel);
|
m_ui->roster->setModel(&rosterModel);
|
||||||
@ -62,6 +63,18 @@ Squawk::Squawk(QWidget *parent) :
|
|||||||
if (testAttribute(Qt::WA_TranslucentBackground)) {
|
if (testAttribute(Qt::WA_TranslucentBackground)) {
|
||||||
m_ui->roster->viewport()->setAutoFillBackground(false);
|
m_ui->roster->viewport()->setAutoFillBackground(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSettings settings;
|
||||||
|
settings.beginGroup("ui");
|
||||||
|
settings.beginGroup("window");
|
||||||
|
if (settings.contains("geometry")) {
|
||||||
|
restoreGeometry(settings.value("geometry").toByteArray());
|
||||||
|
}
|
||||||
|
if (settings.contains("state")) {
|
||||||
|
restoreState(settings.value("state").toByteArray());
|
||||||
|
}
|
||||||
|
settings.endGroup();
|
||||||
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
Squawk::~Squawk() {
|
Squawk::~Squawk() {
|
||||||
@ -871,14 +884,6 @@ void Squawk::readSettings()
|
|||||||
{
|
{
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.beginGroup("ui");
|
settings.beginGroup("ui");
|
||||||
settings.beginGroup("window");
|
|
||||||
if (settings.contains("geometry")) {
|
|
||||||
restoreGeometry(settings.value("geometry").toByteArray());
|
|
||||||
}
|
|
||||||
if (settings.contains("state")) {
|
|
||||||
restoreState(settings.value("state").toByteArray());
|
|
||||||
}
|
|
||||||
settings.endGroup();
|
|
||||||
|
|
||||||
if (settings.contains("availability")) {
|
if (settings.contains("availability")) {
|
||||||
int avail = settings.value("availability").toInt();
|
int avail = settings.value("availability").toInt();
|
||||||
@ -958,3 +963,48 @@ void Squawk::onItemCollepsed(const QModelIndex& index)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Squawk::requestPassword(const QString& account)
|
||||||
|
{
|
||||||
|
requestedAccountsForPasswords.push_back(account);
|
||||||
|
checkNextAccountForPassword();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Squawk::checkNextAccountForPassword()
|
||||||
|
{
|
||||||
|
if (prompt == 0 && requestedAccountsForPasswords.size() > 0) {
|
||||||
|
prompt = new QInputDialog(this);
|
||||||
|
QString accName = requestedAccountsForPasswords.front();
|
||||||
|
connect(prompt, &QDialog::accepted, this, &Squawk::onPasswordPromptAccepted);
|
||||||
|
connect(prompt, &QDialog::rejected, this, &Squawk::onPasswordPromptRejected);
|
||||||
|
prompt->setInputMode(QInputDialog::TextInput);
|
||||||
|
prompt->setTextEchoMode(QLineEdit::Password);
|
||||||
|
prompt->setLabelText(tr("Input the password for account %1").arg(accName));
|
||||||
|
prompt->setWindowTitle(tr("Password for account %1").arg(accName));
|
||||||
|
prompt->setTextValue("");
|
||||||
|
prompt->exec();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Squawk::onPasswordPromptAccepted()
|
||||||
|
{
|
||||||
|
emit responsePassword(requestedAccountsForPasswords.front(), prompt->textValue());
|
||||||
|
onPasswordPromptDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Squawk::onPasswordPromptDone()
|
||||||
|
{
|
||||||
|
prompt->deleteLater();
|
||||||
|
prompt = 0;
|
||||||
|
requestedAccountsForPasswords.pop_front();
|
||||||
|
checkNextAccountForPassword();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Squawk::onPasswordPromptRejected()
|
||||||
|
{
|
||||||
|
//for now it's the same on reject and on accept, but one day I'm gonna make
|
||||||
|
//"Asking for the password again on the authentication failure" feature
|
||||||
|
//and here I'll be able to break the circle of password requests
|
||||||
|
emit responsePassword(requestedAccountsForPasswords.front(), prompt->textValue());
|
||||||
|
onPasswordPromptDone();
|
||||||
|
}
|
||||||
|
10
ui/squawk.h
10
ui/squawk.h
@ -24,6 +24,7 @@
|
|||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
#include <QtDBus/QDBusInterface>
|
#include <QtDBus/QDBusInterface>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
|
#include <QInputDialog>
|
||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -79,6 +80,7 @@ signals:
|
|||||||
void downloadFileRequest(const QString& messageId, const QString& url);
|
void downloadFileRequest(const QString& messageId, const QString& url);
|
||||||
void requestVCard(const QString& account, const QString& jid);
|
void requestVCard(const QString& account, const QString& jid);
|
||||||
void uploadVCard(const QString& account, const Shared::VCard& card);
|
void uploadVCard(const QString& account, const Shared::VCard& card);
|
||||||
|
void responsePassword(const QString& account, const QString& password);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void readSettings();
|
void readSettings();
|
||||||
@ -107,6 +109,7 @@ public slots:
|
|||||||
void fileProgress(const QString& messageId, qreal value);
|
void fileProgress(const QString& messageId, qreal value);
|
||||||
void responseVCard(const QString& jid, const Shared::VCard& card);
|
void responseVCard(const QString& jid, const Shared::VCard& card);
|
||||||
void changeMessage(const QString& account, const QString& jid, const QString& id, const QMap<QString, QVariant>& data);
|
void changeMessage(const QString& account, const QString& jid, const QString& id, const QMap<QString, QVariant>& data);
|
||||||
|
void requestPassword(const QString& account);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef std::map<Models::Roster::ElId, Conversation*> Conversations;
|
typedef std::map<Models::Roster::ElId, Conversation*> Conversations;
|
||||||
@ -119,6 +122,8 @@ private:
|
|||||||
QDBusInterface dbus;
|
QDBusInterface dbus;
|
||||||
std::map<QString, std::set<Models::Roster::ElId>> requestedFiles;
|
std::map<QString, std::set<Models::Roster::ElId>> requestedFiles;
|
||||||
std::map<QString, VCard*> vCards;
|
std::map<QString, VCard*> vCards;
|
||||||
|
std::deque<QString> requestedAccountsForPasswords;
|
||||||
|
QInputDialog* prompt;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void closeEvent(QCloseEvent * event) override;
|
void closeEvent(QCloseEvent * event) override;
|
||||||
@ -146,7 +151,12 @@ private slots:
|
|||||||
void onConversationRequestLocalFile(const QString& messageId, const QString& url);
|
void onConversationRequestLocalFile(const QString& messageId, const QString& url);
|
||||||
void onConversationDownloadFile(const QString& messageId, const QString& url);
|
void onConversationDownloadFile(const QString& messageId, const QString& url);
|
||||||
void onItemCollepsed(const QModelIndex& index);
|
void onItemCollepsed(const QModelIndex& index);
|
||||||
|
void onPasswordPromptAccepted();
|
||||||
|
void onPasswordPromptRejected();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void checkNextAccountForPassword();
|
||||||
|
void onPasswordPromptDone();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SQUAWK_H
|
#endif // SQUAWK_H
|
||||||
|
Loading…
Reference in New Issue
Block a user