4
1
mirror of https://github.com/QuasarApp/Heart.git synced 2025-05-05 22:19:41 +00:00

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

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

@ -51,13 +51,13 @@ bool Async::waitFor(bool *condition, int timeout) const {
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()) {
return job();
}
if (!await) {
return QMetaObject::invokeMethod(this,
return QMetaObject::invokeMethod(const_cast<Async*>(this),
"asyncHandler",
Qt::QueuedConnection,
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 invockeResult = QMetaObject::invokeMethod(this,
bool invockeResult = QMetaObject::invokeMethod(const_cast<Async*>(this),
"asyncHandler",
Qt::QueuedConnection,
Q_ARG(QH::Async::Job, job),

@ -57,7 +57,7 @@ protected:
* @return true if the job function started correctly. IF the await option is true then
* 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:
/**

@ -16,12 +16,18 @@ namespace QH {
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);
if (array.size() != ptr->write(array)) {
QuasarAppUtils::Params::log("not writed data to socket", QuasarAppUtils::Error);
return false;
}
return true;
}
}

@ -9,7 +9,8 @@
#ifndef DATASENDER_H
#define DATASENDER_H
#include <QObject>
#include "async.h"
class QAbstractSocket;
@ -19,19 +20,28 @@ namespace QH {
* @brief The DataSender class this class create a queue for sendet data to network.
* work on a main thread
*/
class DataSender: public QObject
class DataSender: public Async
{
Q_OBJECT
public:
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
* @param array bytes to send
* @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

@ -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.
CREATE TABLE IF NOT EXISTS MemberPermisions (
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,
FOREIGN KEY(memberId) REFERENCES NetworkMembers(id)

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

@ -250,7 +250,7 @@ protected:
* @param requestData This is data of request.
* @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.

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

@ -78,10 +78,20 @@ public:
*/
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:
void recalcHash();
QString _table;
QVariant _value;
QByteArray _SHA256Hash;
};
/**

@ -214,7 +214,7 @@ QString DBObject::condition() const {
// check all objects fields
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)) {
QVariant::Type type = it.value().value.type();

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

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

@ -25,6 +25,7 @@ public:
PermisionData() = default;
PermisionData(const QVariant& subject, const DbAddress& objcet);
PermisionData(const QVariant& subject, const QString& objectAddress);
friend bool operator == (const PermisionData& left, const PermisionData& right);
unsigned int hash() const override;
@ -39,10 +40,11 @@ public:
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.
*/
const DbAddress &address() const;
const QString &addressHash() const;
/**
* @brief setAddress This method set address of database object.
@ -50,6 +52,12 @@ public:
*/
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
const QVariant &id() const;
@ -63,7 +71,8 @@ private:
QVariant _id;
/// table of target object (second part of key)
DbAddress _address;
QString _addressHash;
};
}

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

@ -17,6 +17,8 @@ namespace QH {
*/
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.
* This class use the in memory mode of the sqlite https://sqlite.org/inmemorydb.html