mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-03-13 20:39:57 +01:00
Move old code out of servent to acl registry; make ACL registry actually
do something. Still needed: a page in settings to manage it
This commit is contained in:
parent
e0f60931f7
commit
8ffd79d764
@ -18,10 +18,11 @@
|
||||
|
||||
#include "aclregistry.h"
|
||||
|
||||
#include <QMutexLocker>
|
||||
#include <QThread>
|
||||
#include <QVariant>
|
||||
|
||||
#include "tomahawksettings.h"
|
||||
#include "tomahawkapp.h"
|
||||
|
||||
#include "utils/logger.h"
|
||||
|
||||
@ -53,17 +54,20 @@ ACLRegistry::~ACLRegistry()
|
||||
|
||||
|
||||
ACLRegistry::ACL
|
||||
ACLRegistry::isAuthorizedPeer( const QString& dbid, ACLRegistry::ACL globalType )
|
||||
ACLRegistry::isAuthorizedPeer( const QString& dbid, ACLRegistry::ACL globalType, const QString &username )
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO;
|
||||
QMutexLocker locker( &m_cacheMutex );
|
||||
if ( QThread::currentThread() != TOMAHAWK_APPLICATION::instance()->thread() )
|
||||
return globalType;
|
||||
|
||||
qDebug() << "Current cache keys =" << m_cache.keys();
|
||||
// qDebug() << "Looking up dbid";
|
||||
if( m_cache.contains( dbid ) )
|
||||
{
|
||||
QVariantHash peerHash = m_cache[ dbid ].toHash();
|
||||
if( peerHash.contains( "global" ) )
|
||||
{
|
||||
registerAlias( dbid, username );
|
||||
return ACLRegistry::ACL( peerHash[ "global" ].toInt() );
|
||||
}
|
||||
|
||||
if ( globalType == ACLRegistry::NotFound )
|
||||
return globalType;
|
||||
@ -71,54 +75,54 @@ ACLRegistry::isAuthorizedPeer( const QString& dbid, ACLRegistry::ACL globalType
|
||||
peerHash[ "global" ] = int( globalType );
|
||||
m_cache[ dbid ] = peerHash;
|
||||
save();
|
||||
registerAlias( dbid, username );
|
||||
return globalType;
|
||||
}
|
||||
|
||||
//not found
|
||||
if ( globalType == ACLRegistry::NotFound )
|
||||
return globalType;
|
||||
ACLRegistry::ACL acl = globalType;
|
||||
tDebug( LOGVERBOSE ) << "ACL is intially" << acl;
|
||||
#ifndef ENABLE_HEADLESS
|
||||
acl = getUserDecision( username );
|
||||
tDebug( LOGVERBOSE ) << "after getUserDecision acl is" << acl;
|
||||
#endif
|
||||
|
||||
if ( acl == ACLRegistry::NotFound || acl == ACLRegistry::AllowOnce || acl == ACLRegistry::DenyOnce )
|
||||
return acl;
|
||||
|
||||
QVariantHash peerHash;
|
||||
peerHash[ "global" ] = int( globalType );
|
||||
peerHash[ "global" ] = int( acl );
|
||||
m_cache[ dbid ] = peerHash;
|
||||
save();
|
||||
return globalType;
|
||||
registerAlias( dbid, username );
|
||||
return acl;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ACLRegistry::registerPeer( const QString& dbid, ACLRegistry::ACL globalType, const QString &username )
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO;
|
||||
if( globalType == ACLRegistry::NotFound )
|
||||
if ( QThread::currentThread() != TOMAHAWK_APPLICATION::instance()->thread() )
|
||||
return;
|
||||
|
||||
if ( globalType == ACLRegistry::NotFound || globalType == ACLRegistry::DenyOnce || globalType == ACLRegistry::AllowOnce )
|
||||
return;
|
||||
|
||||
QMutexLocker locker( &m_cacheMutex );
|
||||
|
||||
QVariantHash peerHash;
|
||||
if( m_cache.contains( dbid ) )
|
||||
if ( m_cache.contains( dbid ) )
|
||||
peerHash = m_cache[ dbid ].toHash();
|
||||
peerHash[ "global" ] = int( globalType );
|
||||
if ( !username.isEmpty() )
|
||||
{
|
||||
if ( peerHash.contains( "usernames" ) )
|
||||
{
|
||||
if ( !peerHash[ "usernames" ].toStringList().contains( username ) )
|
||||
peerHash[ "usernames" ] = peerHash[ "usernames" ].toStringList() + QStringList( username );
|
||||
}
|
||||
else
|
||||
peerHash[ "usernames" ] = QStringList( username );
|
||||
}
|
||||
m_cache[ dbid ] = peerHash;
|
||||
save();
|
||||
registerAlias( dbid, username );
|
||||
}
|
||||
|
||||
|
||||
QPair< QString, ACLRegistry::ACL >
|
||||
ACLRegistry::isAuthorizedUser( const QString &username, ACLRegistry::ACL globalType )
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO;
|
||||
QMutexLocker locker( &m_cacheMutex );
|
||||
if ( QThread::currentThread() != TOMAHAWK_APPLICATION::instance()->thread() )
|
||||
return QPair< QString, ACLRegistry::ACL >( QString(), ACLRegistry::NotFound );
|
||||
|
||||
qDebug() << "Current cache keys =" << m_cache.keys();
|
||||
foreach ( QString dbid, m_cache.keys() )
|
||||
{
|
||||
@ -145,6 +149,31 @@ ACLRegistry::isAuthorizedUser( const QString &username, ACLRegistry::ACL globalT
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ACLRegistry::registerAlias( const QString& dbid, const QString &username )
|
||||
{
|
||||
if ( QThread::currentThread() != TOMAHAWK_APPLICATION::instance()->thread() )
|
||||
return;
|
||||
|
||||
if ( dbid.isEmpty() || username.isEmpty() )
|
||||
return;
|
||||
|
||||
if ( !m_cache.contains( dbid ) )
|
||||
return;
|
||||
|
||||
QVariantHash peerHash = m_cache[ dbid ].toHash();
|
||||
if ( !peerHash.contains( "usernames" ) )
|
||||
peerHash[ "usernames" ] = QStringList( username );
|
||||
else if ( !peerHash[ "usernames" ].toStringList().contains( username ) )
|
||||
peerHash[ "usernames" ] = peerHash[ "usernames" ].toStringList() + QStringList( username );
|
||||
else
|
||||
return;
|
||||
|
||||
m_cache[ dbid ] = peerHash;
|
||||
save();
|
||||
}
|
||||
|
||||
|
||||
// ACLRegistry::ACL
|
||||
// ACLRegistry::isAuthorizedPath( const QString& dbid, const QString& path )
|
||||
// {
|
||||
@ -181,6 +210,43 @@ ACLRegistry::isAuthorizedUser( const QString &username, ACLRegistry::ACL globalT
|
||||
// m_cache[dbid] = peerHash;
|
||||
// }
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
ACLRegistry::ACL
|
||||
ACLRegistry::getUserDecision( const QString &username )
|
||||
{
|
||||
QMessageBox msgBox;
|
||||
msgBox.setIcon( QMessageBox::Question );
|
||||
msgBox.setText( tr( "Connect to Peer?" ) );
|
||||
msgBox.setInformativeText( tr( "Another Tomahawk instance that claims to be owned by %1 is attempting to connect to you. Select whether to allow or deny this connection.\n\nRemember: Only allow peers to connect if you trust who they are and if you have the legal right for them to stream music from you.").arg( username ) );
|
||||
QPushButton *denyButton = msgBox.addButton( tr( "Deny" ), QMessageBox::HelpRole );
|
||||
QPushButton *alwaysDenyButton = msgBox.addButton( tr( "Always Deny" ), QMessageBox::YesRole );
|
||||
QPushButton *allowButton = msgBox.addButton( tr( "Allow" ), QMessageBox::NoRole );
|
||||
QPushButton *alwaysAllowButton = msgBox.addButton( tr( "Always Allow" ), QMessageBox::ActionRole );
|
||||
|
||||
msgBox.setDefaultButton( allowButton );
|
||||
msgBox.setEscapeButton( denyButton );
|
||||
|
||||
msgBox.exec();
|
||||
|
||||
if( msgBox.clickedButton() == denyButton )
|
||||
return ACLRegistry::DenyOnce;
|
||||
else if( msgBox.clickedButton() == alwaysDenyButton )
|
||||
return ACLRegistry::Deny;
|
||||
else if( msgBox.clickedButton() == allowButton )
|
||||
return ACLRegistry::AllowOnce;
|
||||
else if( msgBox.clickedButton() == alwaysAllowButton )
|
||||
return ACLRegistry::Allow;
|
||||
|
||||
//How could we get here?
|
||||
tDebug( LOGVERBOSE ) << "ERROR: returning NotFound";
|
||||
Q_ASSERT( false );
|
||||
return ACLRegistry::NotFound;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
ACLRegistry::save()
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <QMutex>
|
||||
#include <QVariant>
|
||||
|
||||
#include "headlesscheck.h"
|
||||
#include "dllmacro.h"
|
||||
|
||||
class DLLEXPORT ACLRegistry : public QObject
|
||||
@ -39,7 +40,9 @@ public:
|
||||
enum ACL {
|
||||
Allow = 0,
|
||||
Deny = 1,
|
||||
NotFound = 2
|
||||
NotFound = 2,
|
||||
AllowOnce = 3,
|
||||
DenyOnce = 4
|
||||
};
|
||||
|
||||
ACLRegistry( QObject *parent = 0 );
|
||||
@ -50,9 +53,10 @@ public:
|
||||
*
|
||||
* @param dbid DBID of peer
|
||||
* @param globalType Global ACL to store if peer not found; if ACLRegistry::NotFound, does not store the peer Defaults to ACLRegistry::NotFound.
|
||||
* @param username If not empty, will store the given username along with the new ACL value. Defaults to QString().
|
||||
* @return ACLRegistry::ACL
|
||||
**/
|
||||
ACLRegistry::ACL isAuthorizedPeer( const QString &dbid, ACLRegistry::ACL globalType = ACLRegistry::NotFound );
|
||||
ACLRegistry::ACL isAuthorizedPeer( const QString &dbid, ACLRegistry::ACL globalType = ACLRegistry::NotFound, const QString &username = QString() );
|
||||
|
||||
/**
|
||||
* @brief Registers the global ACL value for this peer
|
||||
@ -80,8 +84,12 @@ public:
|
||||
* @param username Username of the peer to be added to the entry
|
||||
* @return void
|
||||
**/
|
||||
void registerAlias( const QString &dbid, QString username );
|
||||
void registerAlias( const QString &dbid, const QString &username );
|
||||
|
||||
#ifndef ENABLE_HEADLESS
|
||||
ACLRegistry::ACL getUserDecision( const QString &username );
|
||||
#endif
|
||||
|
||||
// ACLRegistry::ACL isAuthorizedPath( const QString &dbid, const QString &path );
|
||||
// void authorizePath( const QString &dbid, const QString &path, ACLRegistry::ACL type );
|
||||
|
||||
@ -94,7 +102,6 @@ private:
|
||||
void save();
|
||||
|
||||
QVariantHash m_cache;
|
||||
QMutex m_cacheMutex;
|
||||
|
||||
static ACLRegistry* s_instance;
|
||||
};
|
||||
|
@ -305,34 +305,34 @@ void
|
||||
Servent::readyRead()
|
||||
{
|
||||
Q_ASSERT( this->thread() == QThread::currentThread() );
|
||||
QTcpSocketExtra* sock = (QTcpSocketExtra*)sender();
|
||||
QWeakPointer< QTcpSocketExtra > sock = (QTcpSocketExtra*)sender();
|
||||
|
||||
if( sock->_disowned )
|
||||
if( sock.isNull() || sock.data()->_disowned )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( sock->_msg.isNull() )
|
||||
if( sock.data()->_msg.isNull() )
|
||||
{
|
||||
char msgheader[ Msg::headerSize() ];
|
||||
if( sock->bytesAvailable() < Msg::headerSize() )
|
||||
if( sock.data()->bytesAvailable() < Msg::headerSize() )
|
||||
return;
|
||||
|
||||
sock->read( (char*) &msgheader, Msg::headerSize() );
|
||||
sock->_msg = Msg::begin( (char*) &msgheader );
|
||||
sock.data()->read( (char*) &msgheader, Msg::headerSize() );
|
||||
sock.data()->_msg = Msg::begin( (char*) &msgheader );
|
||||
}
|
||||
|
||||
if( sock->bytesAvailable() < sock->_msg->length() )
|
||||
if( sock.data()->bytesAvailable() < sock.data()->_msg->length() )
|
||||
return;
|
||||
|
||||
QByteArray ba = sock->read( sock->_msg->length() );
|
||||
sock->_msg->fill( ba );
|
||||
Q_ASSERT( sock->_msg->is( Msg::JSON ) );
|
||||
QByteArray ba = sock.data()->read( sock.data()->_msg->length() );
|
||||
sock.data()->_msg->fill( ba );
|
||||
Q_ASSERT( sock.data()->_msg->is( Msg::JSON ) );
|
||||
|
||||
ControlConnection* cc = 0;
|
||||
bool ok;
|
||||
QString key, conntype, nodeid, controlid;
|
||||
QVariantMap m = parser.parse( sock->_msg->payload(), &ok ).toMap();
|
||||
QVariantMap m = parser.parse( sock.data()->_msg->payload(), &ok ).toMap();
|
||||
if( !ok )
|
||||
{
|
||||
tDebug() << "Invalid JSON on new connection, aborting";
|
||||
@ -381,21 +381,31 @@ Servent::readyRead()
|
||||
// they connected to us and want something we are offering
|
||||
if ( conntype == "accept-offer" || conntype == "push-offer" )
|
||||
{
|
||||
sock->_msg.clear();
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << key << nodeid << "socket peer address = " << sock->peerAddress() << "socket peer name = " << sock->peerName();
|
||||
Connection* conn = claimOffer( cc, nodeid, key, sock->peerAddress() );
|
||||
if( !conn )
|
||||
sock.data()->_msg.clear();
|
||||
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << key << nodeid << "socket peer address = " << sock.data()->peerAddress() << "socket peer name = " << sock.data()->peerName();
|
||||
Connection* conn = claimOffer( cc, nodeid, key, sock.data()->peerAddress() );
|
||||
if ( !conn )
|
||||
{
|
||||
tLog() << "claimOffer FAILED, key:" << key << nodeid;
|
||||
goto closeconnection;
|
||||
}
|
||||
tDebug( LOGVERBOSE ) << "claimOffer OK:" << key << nodeid;
|
||||
|
||||
if ( sock.isNull() )
|
||||
{
|
||||
tLog() << "Socket has become null, possibly took too long to make an ACL decision, key:" << key << nodeid;
|
||||
return;
|
||||
}
|
||||
else if ( !sock.data()->isValid() )
|
||||
{
|
||||
tLog() << "Socket has become invalid, possibly took too long to make an ACL decision, key:" << key << nodeid;
|
||||
goto closeconnection;
|
||||
}
|
||||
tDebug( LOGVERBOSE ) << "claimOffer OK:" << key << nodeid;
|
||||
|
||||
m_connectedNodes << nodeid;
|
||||
if( !nodeid.isEmpty() )
|
||||
conn->setId( nodeid );
|
||||
|
||||
handoverSocket( conn, sock );
|
||||
handoverSocket( conn, sock.data() );
|
||||
return;
|
||||
}
|
||||
else
|
||||
@ -406,8 +416,8 @@ Servent::readyRead()
|
||||
// fallthru to cleanup:
|
||||
closeconnection:
|
||||
tLog() << "Closing incoming connection, something was wrong.";
|
||||
sock->_msg.clear();
|
||||
sock->disconnectFromHost();
|
||||
sock.data()->_msg.clear();
|
||||
sock.data()->disconnectFromHost();
|
||||
}
|
||||
|
||||
|
||||
@ -661,7 +671,7 @@ Servent::claimOffer( ControlConnection* cc, const QString &nodeid, const QString
|
||||
if( !nodeid.isEmpty() )
|
||||
{
|
||||
// If there isn't a nodeid it's not the first connection and will already have been stopped
|
||||
if( !checkACL( conn.data(), nodeid, true ) )
|
||||
if( !checkACL( conn, nodeid ) )
|
||||
{
|
||||
tLog() << "Connection not allowed due to ACL";
|
||||
return NULL;
|
||||
@ -694,64 +704,18 @@ Servent::claimOffer( ControlConnection* cc, const QString &nodeid, const QString
|
||||
|
||||
|
||||
bool
|
||||
Servent::checkACL( const Connection* conn, const QString &nodeid, bool showDialog ) const
|
||||
Servent::checkACL( const QWeakPointer< Connection > conn, const QString &nodeid ) const
|
||||
{
|
||||
Q_UNUSED( conn );
|
||||
Q_UNUSED( nodeid );
|
||||
Q_UNUSED( showDialog );
|
||||
|
||||
/*
|
||||
tDebug( LOGVERBOSE ) << "Checking ACLs";
|
||||
ACLSystem* aclSystem = ACLSystem::instance();
|
||||
ACLSystem::ACL peerStatus = aclSystem->isAuthorizedUser( nodeid );
|
||||
if( peerStatus == ACLSystem::Deny )
|
||||
if ( conn.isNull() )
|
||||
return false;
|
||||
|
||||
tDebug( LOGVERBOSE ) << "Checking ACL for" << conn.data()->name();
|
||||
ACLRegistry::ACL peerStatus = ACLRegistry::instance()->isAuthorizedPeer( nodeid, ACLRegistry::NotFound, conn.data()->name() );
|
||||
tDebug( LOGVERBOSE ) << "ACL status is" << peerStatus;
|
||||
if ( peerStatus == ACLRegistry::Allow || peerStatus == ACLRegistry::AllowOnce )
|
||||
return true;
|
||||
|
||||
//FIXME: Actually enable it when it makes sense
|
||||
//FIXME: needs refactoring because it depends on QtGui and the servent is part of libtomahawk-core
|
||||
|
||||
return true;
|
||||
if( peerStatus == ACLSystem::NotFound )
|
||||
{
|
||||
if( !showDialog )
|
||||
return false;
|
||||
|
||||
QMessageBox msgBox;
|
||||
msgBox.setIcon( QMessageBox::Question );
|
||||
msgBox.setText( tr( "Incoming Connection Attempt" ) );
|
||||
msgBox.setInformativeText( tr( "Another Tomahawk instance is attempting to connect to you. Select whether to allow or deny this connection.\n\nPeer name: %1\nPeer ID: %2\n\nRemember: Only allow peers to connect if you have the legal right for them to stream music from you.").arg( conn->name(), nodeid ) );
|
||||
QPushButton *denyButton = msgBox.addButton( tr( "Deny" ), QMessageBox::HelpRole );
|
||||
QPushButton *alwaysDenyButton = msgBox.addButton( tr( "Always Deny" ), QMessageBox::YesRole );
|
||||
QPushButton *allowButton = msgBox.addButton( tr( "Allow" ), QMessageBox::NoRole );
|
||||
QPushButton *alwaysAllowButton = msgBox.addButton( tr( "Always Allow" ), QMessageBox::ActionRole );
|
||||
|
||||
msgBox.setDefaultButton( denyButton );
|
||||
msgBox.setEscapeButton( denyButton );
|
||||
|
||||
msgBox.exec();
|
||||
|
||||
if( msgBox.clickedButton() == denyButton )
|
||||
return false;
|
||||
else if( msgBox.clickedButton() == alwaysDenyButton )
|
||||
{
|
||||
aclSystem->authorizeUser( nodeid, ACLSystem::Deny );
|
||||
return false;
|
||||
}
|
||||
else if( msgBox.clickedButton() == alwaysAllowButton )
|
||||
{
|
||||
aclSystem->authorizeUser( nodeid, ACLSystem::Allow );
|
||||
return true;
|
||||
}
|
||||
else if( msgBox.clickedButton() == allowButton )
|
||||
return true;
|
||||
|
||||
//How could we get here?
|
||||
Q_ASSERT( false );
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -110,7 +110,7 @@ public:
|
||||
QString externalAddress() const { return !m_externalHostname.isNull() ? m_externalHostname : m_externalAddress.toString(); }
|
||||
int externalPort() const { return m_externalPort; }
|
||||
|
||||
QSharedPointer<QIODevice> remoteIODeviceFactory( const Tomahawk::result_ptr& );
|
||||
QSharedPointer< QIODevice > remoteIODeviceFactory( const Tomahawk::result_ptr& );
|
||||
static bool isIPWhitelisted( QHostAddress ip );
|
||||
|
||||
bool connectedToSession( const QString& session );
|
||||
@ -118,10 +118,10 @@ public:
|
||||
|
||||
QList< StreamConnection* > streams() const { return m_scsessions; }
|
||||
|
||||
QSharedPointer<QIODevice> getIODeviceForUrl( const Tomahawk::result_ptr& result );
|
||||
void registerIODeviceFactory( const QString &proto, boost::function<QSharedPointer<QIODevice>(Tomahawk::result_ptr)> fac );
|
||||
QSharedPointer<QIODevice> localFileIODeviceFactory( const Tomahawk::result_ptr& result );
|
||||
QSharedPointer<QIODevice> httpIODeviceFactory( const Tomahawk::result_ptr& result );
|
||||
QSharedPointer< QIODevice > getIODeviceForUrl( const Tomahawk::result_ptr& result );
|
||||
void registerIODeviceFactory( const QString &proto, boost::function< QSharedPointer< QIODevice >(Tomahawk::result_ptr) > fac );
|
||||
QSharedPointer< QIODevice > localFileIODeviceFactory( const Tomahawk::result_ptr& result );
|
||||
QSharedPointer< QIODevice > httpIODeviceFactory( const Tomahawk::result_ptr& result );
|
||||
|
||||
bool isReady() const { return m_ready; };
|
||||
|
||||
@ -154,12 +154,12 @@ private slots:
|
||||
private:
|
||||
bool isValidExternalIP( const QHostAddress& addr ) const;
|
||||
void handoverSocket( Connection* conn, QTcpSocketExtra* sock );
|
||||
bool checkACL( const Connection* conn, const QString &nodeid, bool showDialog ) const;
|
||||
bool checkACL( const QWeakPointer< Connection > conn, const QString &nodeid ) const;
|
||||
void printCurrentTransfers();
|
||||
|
||||
QJson::Parser parser;
|
||||
QList< ControlConnection* > m_controlconnections; // canonical list of authed peers
|
||||
QMap< QString, QWeakPointer<Connection> > m_offers;
|
||||
QMap< QString, QWeakPointer< Connection > > m_offers;
|
||||
QStringList m_connectedNodes;
|
||||
|
||||
int m_port, m_externalPort;
|
||||
@ -172,7 +172,7 @@ private:
|
||||
QList< StreamConnection* > m_scsessions;
|
||||
QMutex m_ftsession_mut;
|
||||
|
||||
QMap< QString,boost::function<QSharedPointer<QIODevice>(Tomahawk::result_ptr)> > m_iofactories;
|
||||
QMap< QString,boost::function< QSharedPointer< QIODevice >(Tomahawk::result_ptr) > > m_iofactories;
|
||||
|
||||
PortFwdThread* m_portfwd;
|
||||
static Servent* s_instance;
|
||||
|
Loading…
x
Reference in New Issue
Block a user