fix permissions control

This commit is contained in:
Andrei Yankovich 2021-02-19 18:59:00 +03:00
parent 93cf082080
commit f135c38e7c
16 changed files with 107 additions and 59 deletions

View File

@ -377,7 +377,7 @@ bool AbstractNode::registerSocket(QAbstractSocket *socket, const HostAddress* cl
ParserResult AbstractNode::parsePackage(const Package &pkg, ParserResult AbstractNode::parsePackage(const Package &pkg,
const AbstractNodeInfo *sender) { const AbstractNodeInfo *sender) {
if (!(sender && sender->isValid())) { if (!(sender)) {
QuasarAppUtils::Params::log("sender socket is not valid!", QuasarAppUtils::Params::log("sender socket is not valid!",
QuasarAppUtils::Error); QuasarAppUtils::Error);
return ParserResult::Error; return ParserResult::Error;
@ -436,12 +436,7 @@ bool AbstractNode::sendPackage(const Package &pkg, QAbstractSocket *target) cons
return false; return false;
} }
return QMetaObject::invokeMethod(const_cast<DataSender*>(_dataSender), return _dataSender->sendData(pkg.toBytes(), target, true);
"sendPackagePrivate",
Qt::QueuedConnection,
Q_ARG(QByteArray, pkg.toBytes()),
Q_ARG(void*, target));
} }
bool AbstractNode::sendData(AbstractData *resp, bool AbstractNode::sendData(AbstractData *resp,

View File

@ -51,13 +51,13 @@ bool Async::waitFor(bool *condition, int timeout) const {
waitPrivate(*condition, timeout) waitPrivate(*condition, timeout)
} }
bool Async::asyncLauncher(const Async::Job &job, bool await) { bool Async::asyncLauncher(const Async::Job &job, bool await) const {
if (QThread::currentThread() == thread()) { if (QThread::currentThread() == thread()) {
return job(); return job();
} }
if (!await) { if (!await) {
return QMetaObject::invokeMethod(this, return QMetaObject::invokeMethod(const_cast<Async*>(this),
"asyncHandler", "asyncHandler",
Qt::QueuedConnection, Qt::QueuedConnection,
Q_ARG(QH::Async::Job, job)); Q_ARG(QH::Async::Job, job));
@ -65,7 +65,7 @@ bool Async::asyncLauncher(const Async::Job &job, bool await) {
bool workOfEnd = false, workResult = false; bool workOfEnd = false, workResult = false;
bool invockeResult = QMetaObject::invokeMethod(this, bool invockeResult = QMetaObject::invokeMethod(const_cast<Async*>(this),
"asyncHandler", "asyncHandler",
Qt::QueuedConnection, Qt::QueuedConnection,
Q_ARG(QH::Async::Job, job), Q_ARG(QH::Async::Job, job),

View File

@ -57,7 +57,7 @@ protected:
* @return true if the job function started correctly. IF the await option is true then * @return true if the job function started correctly. IF the await option is true then
* this method return result of job function. * this method return result of job function.
*/ */
bool asyncLauncher(const Job &job, bool await = false); bool asyncLauncher(const Job &job, bool await = false) const;
private slots: private slots:
/** /**

View File

@ -16,12 +16,18 @@ namespace QH {
DataSender::DataSender() { DataSender::DataSender() {
} }
void QH::DataSender::sendPackagePrivate(QByteArray array, void *target) const { bool DataSender::sendData(const QByteArray &array, void *target, bool await) const {
return asyncLauncher(std::bind(&DataSender::sendPackagePrivate, this, array, target), await);
}
bool QH::DataSender::sendPackagePrivate(QByteArray array, void *target) const {
auto ptr = static_cast<QAbstractSocket*>(target); auto ptr = static_cast<QAbstractSocket*>(target);
if (array.size() != ptr->write(array)) { if (array.size() != ptr->write(array)) {
QuasarAppUtils::Params::log("not writed data to socket", QuasarAppUtils::Error); QuasarAppUtils::Params::log("not writed data to socket", QuasarAppUtils::Error);
return false;
} }
return true;
} }
} }

View File

@ -9,7 +9,8 @@
#ifndef DATASENDER_H #ifndef DATASENDER_H
#define DATASENDER_H #define DATASENDER_H
#include <QObject> #include "async.h"
class QAbstractSocket; class QAbstractSocket;
@ -19,19 +20,28 @@ namespace QH {
* @brief The DataSender class this class create a queue for sendet data to network. * @brief The DataSender class this class create a queue for sendet data to network.
* work on a main thread * work on a main thread
*/ */
class DataSender: public QObject class DataSender: public Async
{ {
Q_OBJECT Q_OBJECT
public: public:
DataSender(); DataSender();
public slots: /**
* @brief sendPackagePrivate This slot move send package to a main threan
* @param array bytes to send
* @param target This is pointer of target socket
* @param await This option force wait for finishing data sending.
*/
bool sendData(const QByteArray &array, void *target, bool await = false) const;
private:
/** /**
* @brief sendPackagePrivate This slot move send package to a main threan * @brief sendPackagePrivate This slot move send package to a main threan
* @param array bytes to send * @param array bytes to send
* @param target - this is pointer of target socket * @param target - this is pointer of target socket
*/ */
void sendPackagePrivate(QByteArray array, void *target) const; bool sendPackagePrivate(QByteArray array, void *target) const;
}; };
} }
#endif // DATASENDER_H #endif // DATASENDER_H

View File

@ -9,7 +9,8 @@ CREATE TABLE IF NOT EXISTS NetworkMembers (
-- The MemberPermisions table contains link to anothe database object and links to users of the database with permission lvl. -- The MemberPermisions table contains link to anothe database object and links to users of the database with permission lvl.
CREATE TABLE IF NOT EXISTS MemberPermisions ( CREATE TABLE IF NOT EXISTS MemberPermisions (
memberId VARCHAR(32) NOT NULL, memberId VARCHAR(32) NOT NULL,
dbAddress BLOB NOT NULL, -- This field contatins a base64 implementation of a sha256 (requariment 44 bytes) hash code of a database address
dbAddress VARCHAR(44) NOT NULL,
lvl tinyint NOT NULL, lvl tinyint NOT NULL,
FOREIGN KEY(memberId) REFERENCES NetworkMembers(id) FOREIGN KEY(memberId) REFERENCES NetworkMembers(id)

View File

@ -244,7 +244,6 @@ ParserResult DataBaseNode::parsePackage(const Package &pkg,
WebSocket obj(pkg); WebSocket obj(pkg);
QVariant requesterId = getSender(sender, &obj); QVariant requesterId = getSender(sender, &obj);
if (!obj.isValid()) { if (!obj.isValid()) {
badRequest(sender->networkAddress(), pkg.hdr, badRequest(sender->networkAddress(), pkg.hdr,
{ {
@ -280,7 +279,6 @@ ParserResult DataBaseNode::parsePackage(const Package &pkg,
auto obj = QSharedPointer<DeleteObject>::create(pkg); auto obj = QSharedPointer<DeleteObject>::create(pkg);
auto requesterId = getSender(sender, obj.data()); auto requesterId = getSender(sender, obj.data());
if (deleteObject(requesterId, obj) == DBOperationResult::Forbidden) { if (deleteObject(requesterId, obj) == DBOperationResult::Forbidden) {
badRequest(sender->networkAddress(), pkg.hdr, { badRequest(sender->networkAddress(), pkg.hdr, {
ErrorCodes::OperatioForbiden, ErrorCodes::OperatioForbiden,
@ -493,15 +491,14 @@ DataBaseNode::changeObjects(const QVariant &requester,
return result; return result;
} }
const QVariant* DataBaseNode::getSender(const AbstractNodeInfo *connectInfo, QVariant DataBaseNode::getSender(const AbstractNodeInfo *connectInfo,
const AbstractData *) const { const AbstractData *) const {
auto info = dynamic_cast<const BaseNodeInfo*>(connectInfo); auto info = dynamic_cast<const BaseNodeInfo*>(connectInfo);
if (!info) if (!info)
return nullptr; return {};
return &info->id(); return info->id();
} }
DBOperationResult DBOperationResult
@ -509,18 +506,14 @@ DataBaseNode::checkPermission(const QVariant &requester,
const DbAddress &objectAddress, const DbAddress &objectAddress,
const Permission& requarimentPermision) const { const Permission& requarimentPermision) const {
if (!requester.isValid())
return DBOperationResult::Unknown;
if (!_db) { if (!_db) {
return DBOperationResult::Unknown; return DBOperationResult::Unknown;
} }
auto tmp = _db->getObjectRaw(NetworkMember{requester}); auto member = _db->getObjectRaw(NetworkMember{requester});
if (!tmp) {
return DBOperationResult::Unknown;
}
auto member = tmp.dynamicCast<AbstractNetworkMember>();
if (!member) { if (!member) {
return DBOperationResult::Unknown; return DBOperationResult::Unknown;
} }

View File

@ -250,7 +250,7 @@ protected:
* @param requestData This is data of request. * @param requestData This is data of request.
* @return id of requester member. * @return id of requester member.
*/ */
virtual const QVariant *getSender(const AbstractNodeInfo *connectInfo, const PKG::AbstractData *requestData) const; virtual QVariant getSender(const AbstractNodeInfo *connectInfo, const PKG::AbstractData *requestData) const;
/** /**
* @brief checkPermision This method check a permision of requester to database object with objectAddress. * @brief checkPermision This method check a permision of requester to database object with objectAddress.

View File

@ -8,17 +8,20 @@
#include "dbaddress.h" #include "dbaddress.h"
#include <QDataStream> #include <QDataStream>
#include <QHash> #include <QHash>
#include <QCryptographicHash>
namespace QH { namespace QH {
qint64 qHash(const DbAddress &address) { qint64 qHash(const DbAddress &address) {
return qHash(address.table() + address.id().toString()); return qHash(address.SHA256Hash());
} }
DbAddress::DbAddress(const QString &table, const QVariant &id) { DbAddress::DbAddress(const QString &table, const QVariant &id) {
this->_table = table; this->_table = table;
this->_value = id; this->_value = id;
recalcHash();
} }
bool operator==(const DbAddress & left, const DbAddress &other) { bool operator==(const DbAddress & left, const DbAddress &other) {
@ -28,6 +31,8 @@ bool operator==(const DbAddress & left, const DbAddress &other) {
QDataStream &DbAddress::fromStream(QDataStream &stream) { QDataStream &DbAddress::fromStream(QDataStream &stream) {
stream >> _value; stream >> _value;
stream >> _table; stream >> _table;
recalcHash();
return stream; return stream;
} }
@ -38,8 +43,8 @@ QDataStream &DbAddress::toStream(QDataStream &stream) const {
} }
QString DbAddress::toString() const { QString DbAddress::toString() const {
return QString("DbAddress: table:%0, value:%1"). return QString("DbAddress: table:%0, value:%1, Sha256:%2").
arg(_table, _value.toString()); arg(_table, _value.toString(), _SHA256Hash.toHex());
} }
bool operator!=(const DbAddress &left, const DbAddress &other) { bool operator!=(const DbAddress &left, const DbAddress &other) {
@ -56,6 +61,7 @@ const QString& DbAddress::table() const {
void DbAddress::setTable(const QString &table) { void DbAddress::setTable(const QString &table) {
_table = table; _table = table;
recalcHash();
} }
const QVariant &DbAddress::id() const { const QVariant &DbAddress::id() const {
@ -64,6 +70,15 @@ const QVariant &DbAddress::id() const {
void DbAddress::setId(const QVariant &id){ void DbAddress::setId(const QVariant &id){
_value = id; _value = id;
recalcHash();
}
QByteArray DbAddress::SHA256Hash() const {
return _SHA256Hash;
}
void DbAddress::recalcHash() {
_SHA256Hash = QCryptographicHash::hash(toBytes(), QCryptographicHash::Sha256);
} }
} }

View File

@ -78,10 +78,20 @@ public:
*/ */
void setId(const QVariant &id); void setId(const QVariant &id);
/**
* @brief SHA256Hash This method return address hash.
* This hash using into database.
* @return return array of the hash of this address.
*/
QByteArray SHA256Hash() const;
private: private:
void recalcHash();
QString _table; QString _table;
QVariant _value; QVariant _value;
QByteArray _SHA256Hash;
}; };
/** /**

View File

@ -214,7 +214,7 @@ QString DBObject::condition() const {
// check all objects fields // check all objects fields
for (auto it = map.begin(); it != map.end(); ++it) { for (auto it = map.begin(); it != map.end(); ++it) {
// if field if unique then to // if field is unique then
if (bool(it.value().type & MemberType::Unique)) { if (bool(it.value().type & MemberType::Unique)) {
QVariant::Type type = it.value().value.type(); QVariant::Type type = it.value().value.type();

View File

@ -58,13 +58,12 @@ uint MemberPermisionObject::dbKey() const {
bool MemberPermisionObject::fromSqlRecord(const QSqlRecord &q) { bool MemberPermisionObject::fromSqlRecord(const QSqlRecord &q) {
DbAddress address; PermisionData permision(q.value("memberId"),
address.fromBytes(q.value("dbAddress").toByteArray()); q.value("dbAddress").toString());
PermisionData permision(q.value("memberId"), address); setKey(permision);
setPermisions(static_cast<Permission>(q.value("lvl").toUInt())); setPermisions(static_cast<Permission>(q.value("lvl").toUInt()));
return isValid(); return isValid();
} }
@ -89,7 +88,7 @@ QDataStream &MemberPermisionObject::toStream(QDataStream &stream) const {
DBVariantMap MemberPermisionObject::variantMap() const { DBVariantMap MemberPermisionObject::variantMap() const {
return {{"memberId", {_key.id(), MemberType::InsertUpdate}}, return {{"memberId", {_key.id(), MemberType::InsertUpdate}},
{"dbAddress", {_key.address().toBytes(), MemberType::InsertUpdate}}, {"dbAddress", {_key.addressHash(), MemberType::InsertUpdate}},
{"lvl", {static_cast<unsigned char>(_permision), MemberType::InsertUpdate}}}; {"lvl", {static_cast<unsigned char>(_permision), MemberType::InsertUpdate}}};
} }
@ -101,9 +100,9 @@ QString MemberPermisionObject::condition() const {
if (_key.id().isValid()) { if (_key.id().isValid()) {
if (result.size()) { if (result.size()) {
result += ", "; result += " AND ";
} }
result += "dbAddress=" + _key.address().toBytes(); result += "dbAddress='" + _key.addressHash()+ "'";
} }
return result; return result;

View File

@ -15,7 +15,7 @@
namespace QH { namespace QH {
bool operator ==(const PermisionData &left, const PermisionData &right) { bool operator ==(const PermisionData &left, const PermisionData &right) {
return left._id == right._id && left._address == right._address; return left._id == right._id && left._addressHash == right._addressHash;
} }
PermisionData::PermisionData(const QVariant &subject, const DbAddress &objcet) { PermisionData::PermisionData(const QVariant &subject, const DbAddress &objcet) {
@ -23,17 +23,22 @@ PermisionData::PermisionData(const QVariant &subject, const DbAddress &objcet) {
setAddress(objcet); setAddress(objcet);
} }
PermisionData::PermisionData(const QVariant &subject, const QString &objectAddress) {
setId(subject);
setAddress(objectAddress);
}
unsigned int PermisionData::hash() const { unsigned int PermisionData::hash() const {
QByteArray data; QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly); QDataStream stream(&data, QIODevice::WriteOnly);
stream << _id; stream << _id;
stream << _address; stream << _addressHash;
return qHash(data); return qHash(data);
} }
bool PermisionData::isValid() const { bool PermisionData::isValid() const {
return address().isValid() && _id.isValid(); return _addressHash.size() && _id.isValid();
} }
bool PermisionData::equal(const AbstractKey *other) const { bool PermisionData::equal(const AbstractKey *other) const {
@ -41,32 +46,36 @@ bool PermisionData::equal(const AbstractKey *other) const {
if (!otherObject) if (!otherObject)
return false; return false;
return _address == otherObject->_address && _id == otherObject->_id; return _addressHash == otherObject->_addressHash && _id == otherObject->_id;
} }
QString PermisionData::toString() const { QString PermisionData::toString() const {
return QString("DBAddress: %0, Owner Id: %1"). return QString("DBAddressHash: %0, Owner Id: %1").
arg(_address.toString(), _id.toString()); arg(_addressHash, _id.toString());
} }
const DbAddress& PermisionData::address() const { const QString& PermisionData::addressHash() const {
return _address; return _addressHash;
} }
void PermisionData::setAddress(const DbAddress &address) { void PermisionData::setAddress(const DbAddress &address) {
_address = address; setAddress(address.SHA256Hash().toBase64(QByteArray::Base64UrlEncoding));
}
void PermisionData::setAddress(const QString &addressHash) {
_addressHash = addressHash;
} }
QDataStream &PermisionData::fromStream(QDataStream &stream) { QDataStream &PermisionData::fromStream(QDataStream &stream) {
stream >> _id; stream >> _id;
stream >> _address; stream >> _addressHash;
return stream; return stream;
} }
QDataStream &PermisionData::toStream(QDataStream &stream) const { QDataStream &PermisionData::toStream(QDataStream &stream) const {
stream << _id; stream << _id;
stream << _address; stream << _addressHash;
return stream; return stream;
} }

View File

@ -25,6 +25,7 @@ public:
PermisionData() = default; PermisionData() = default;
PermisionData(const QVariant& subject, const DbAddress& objcet); PermisionData(const QVariant& subject, const DbAddress& objcet);
PermisionData(const QVariant& subject, const QString& objectAddress);
friend bool operator == (const PermisionData& left, const PermisionData& right); friend bool operator == (const PermisionData& left, const PermisionData& right);
unsigned int hash() const override; unsigned int hash() const override;
@ -39,10 +40,11 @@ public:
void setId(const QVariant &Id); void setId(const QVariant &Id);
/** /**
* @brief address This method return address of database object. * @brief addressHash This method return sha256 hash of the address of database object.
* The hash encoded as a base64.
* @return address of database object. * @return address of database object.
*/ */
const DbAddress &address() const; const QString &addressHash() const;
/** /**
* @brief setAddress This method set address of database object. * @brief setAddress This method set address of database object.
@ -50,6 +52,12 @@ public:
*/ */
void setAddress(const DbAddress &address); void setAddress(const DbAddress &address);
/**
* @brief setAddress This implementation sets sh256 hash og the address (hash must be write in base64 encoding)
* @param address This is base64 string of a sh256 hash code.
*/
void setAddress(const QString &addressHash);
// StreamBase interface // StreamBase interface
const QVariant &id() const; const QVariant &id() const;
@ -63,7 +71,8 @@ private:
QVariant _id; QVariant _id;
/// table of target object (second part of key) /// table of target object (second part of key)
DbAddress _address; QString _addressHash;
}; };
} }

View File

@ -196,8 +196,7 @@ bool SingleServer::workWithUserRequest(const QSharedPointer<PKG::UserMember>& ob
} else if (request->getRequestCmd() == static_cast<quint8>(PKG::UserRequestType::Remove)) { } else if (request->getRequestCmd() == static_cast<quint8>(PKG::UserRequestType::Remove)) {
auto requesterId = getSender(sender, obj.data()); auto requesterId = getSender(sender, obj.data());
if (deleteObject(requesterId, obj) != DBOperationResult::Allowed) {
if (requesterId && deleteObject(requesterId, obj) != DBOperationResult::Allowed) {
prepareAndSendBadRequest(sender->networkAddress(), pkg.hdr, prepareAndSendBadRequest(sender->networkAddress(), pkg.hdr,
ErrorCodes::OperatioForbiden, REQUEST_ERROR); ErrorCodes::OperatioForbiden, REQUEST_ERROR);
} }

View File

@ -17,6 +17,8 @@ namespace QH {
*/ */
class SQLiteDBCachePrivate; class SQLiteDBCachePrivate;
// TO-DO see task https://github.com/QuasarApp/Heart/issues/15
/** /**
* @brief The SQLiteDBCache class using sqliete database for save all temp values. * @brief The SQLiteDBCache class using sqliete database for save all temp values.
* This class use the in memory mode of the sqlite https://sqlite.org/inmemorydb.html * This class use the in memory mode of the sqlite https://sqlite.org/inmemorydb.html