Half of invitation works
diff --git a/src/contactpanel.cpp b/src/contactpanel.cpp
index e2c8359..4ba7323 100644
--- a/src/contactpanel.cpp
+++ b/src/contactpanel.cpp
@@ -18,62 +18,96 @@
#include <QDir>
#ifndef Q_MOC_RUN
+#include <ndn.cxx/security/keychain.h>
+#include <ndn.cxx/security/identity/osx-privatekey-storage.h>
+#include <ndn.cxx/security/identity/identity-manager.h>
+#include <ndn.cxx/security/identity/basic-identity-storage.h>
+#include <ndn.cxx/security/cache/ttl-certificate-cache.h>
+#include <ndn.cxx/security/encryption/basic-encryption-manager.h>
#include <ndn.cxx/common.h>
#include <boost/filesystem.hpp>
+#include <boost/random/random_device.hpp>
+#include <boost/random/uniform_int_distribution.hpp>
+#include "invitation-policy-manager.h"
#include "logging.h"
#include "exception.h"
#endif
namespace fs = boost::filesystem;
using namespace ndn;
+
using namespace std;
INIT_LOGGER("ContactPanel");
+Q_DECLARE_METATYPE(ndn::security::IdentityCertificate)
+
ContactPanel::ContactPanel(Ptr<ContactManager> contactManager, QWidget *parent)
: QDialog(parent)
, ui(new Ui::ContactPanel)
, m_contactManager(contactManager)
, m_contactListModel(new QStringListModel)
+ , m_profileEditor(new ProfileEditor(m_contactManager))
, m_addContactPanel(new AddContactPanel(contactManager))
, m_setAliasDialog(new SetAliasDialog(contactManager))
, m_startChatDialog(new StartChatDialog)
+ , m_invitationDialog(new InvitationDialog)
+ , m_settingDialog(new SettingDialog)
, m_menuInvite(new QAction("&Chat", this))
, m_menuAlias(new QAction("&Set Alias", this))
{
+ qRegisterMetaType<ndn::security::IdentityCertificate>("IdentityCertificate");
- ui->setupUi(this);
+ ui->setupUi(this);
+ refreshContactList();
- QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
- QString path = (QDir::home().path());
- path.append(QDir::separator()).append(".chronos").append(QDir::separator()).append("chronos.db");
- db.setDatabaseName(path);
- bool ok = db.open();
+ openDB();
- m_profileEditor = new ProfileEditor(m_contactManager);
+ setKeychain();
+ m_handler = Ptr<Wrapper>(new Wrapper(m_keychain));
+
+ setLocalPrefix();
+
+ // Set Identity, TODO: through user interface
+ m_defaultIdentity = m_keychain->getDefaultIdentity();
+ m_settingDialog->setIdentity(m_defaultIdentity.toUri());
+ setInvitationListener();
- refreshContactList();
- ui->ContactList->setModel(m_contactListModel);
+ ui->ContactList->setModel(m_contactListModel);
- QItemSelectionModel* selectionModel = ui->ContactList->selectionModel();
+ QItemSelectionModel* selectionModel = ui->ContactList->selectionModel();
- connect(selectionModel, SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
- this, SLOT(updateSelection(const QItemSelection &, const QItemSelection &)));
- connect(ui->ContactList, SIGNAL(customContextMenuRequested(const QPoint&)),
- this, SLOT(showContextMenu(const QPoint&)));
- connect(ui->EditProfileButton, SIGNAL(clicked()),
- this, SLOT(openProfileEditor()));
+ connect(selectionModel, SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
+ this, SLOT(updateSelection(const QItemSelection &, const QItemSelection &)));
- connect(ui->AddContactButton, SIGNAL(clicked()),
- this, SLOT(openAddContactPanel()));
+ connect(ui->ContactList, SIGNAL(customContextMenuRequested(const QPoint&)),
+ this, SLOT(showContextMenu(const QPoint&)));
- connect(m_addContactPanel, SIGNAL(newContactAdded()),
- this, SLOT(refreshContactList()));
- connect(m_setAliasDialog, SIGNAL(aliasChanged()),
- this, SLOT(refreshContactList()));
+ connect(ui->EditProfileButton, SIGNAL(clicked()),
+ this, SLOT(openProfileEditor()));
- connect(m_startChatDialog, SIGNAL(chatroomConfirmed(const QString&, const QString&, bool)),
- this, SLOT(startChatroom(const QString&, const QString&, bool)));
+ connect(ui->AddContactButton, SIGNAL(clicked()),
+ this, SLOT(openAddContactPanel()));
+
+ connect(ui->settingButton, SIGNAL(clicked()),
+ this, SLOT(openSettingDialog()));
+
+ connect(m_addContactPanel, SIGNAL(newContactAdded()),
+ this, SLOT(refreshContactList()));
+
+ connect(m_setAliasDialog, SIGNAL(aliasChanged()),
+ this, SLOT(refreshContactList()));
+
+ connect(m_startChatDialog, SIGNAL(chatroomConfirmed(const QString&, const QString&, bool)),
+ this, SLOT(startChatroom(const QString&, const QString&, bool)));
+
+ connect(m_invitationDialog, SIGNAL(invitationAccepted(const ndn::Name&, const ndn::security::IdentityCertificate&, QString, QString)),
+ this, SLOT(acceptInvitation(const ndn::Name&, const ndn::security::IdentityCertificate&, QString, QString)));
+ connect(m_invitationDialog, SIGNAL(invitationRejected(const ndn::Name&)),
+ this, SLOT(rejectInvitation(const ndn::Name&)));
+
+ connect(m_settingDialog, SIGNAL(identitySet(const QString&)),
+ this, SLOT(updateDefaultIdentity(const QString&)));
@@ -90,6 +124,204 @@
}
void
+ContactPanel::openDB()
+{
+ QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
+ QString path = (QDir::home().path());
+ path.append(QDir::separator()).append(".chronos").append(QDir::separator()).append("chronos.db");
+ db.setDatabaseName(path);
+ bool ok = db.open();
+}
+
+void
+ContactPanel::setKeychain()
+{
+ Ptr<security::OSXPrivatekeyStorage> privateStorage = Ptr<security::OSXPrivatekeyStorage>::Create();
+ Ptr<security::IdentityManager> identityManager = Ptr<security::IdentityManager>(new security::IdentityManager(Ptr<security::BasicIdentityStorage>::Create(), privateStorage));
+ Ptr<security::CertificateCache> certificateCache = Ptr<security::CertificateCache>(new security::TTLCertificateCache());
+ Ptr<InvitationPolicyManager> policyManager = Ptr<InvitationPolicyManager>(new InvitationPolicyManager(10, certificateCache));
+ Ptr<security::EncryptionManager> encryptionManager = Ptr<security::EncryptionManager>(new security::BasicEncryptionManager(privateStorage, "/tmp/encryption.db"));
+
+ vector<Ptr<ContactItem> >::const_iterator it = m_contactList.begin();
+ for(; it != m_contactList.end(); it++)
+ policyManager->addTrustAnchor((*it)->getSelfEndorseCertificate());
+
+ m_keychain = Ptr<security::Keychain>(new security::Keychain(identityManager, policyManager, encryptionManager));
+}
+
+void
+ContactPanel::setLocalPrefix()
+{
+ Ptr<Interest> interest = Ptr<Interest>(new Interest(Name("/local/ndn/prefix")));
+ interest->setChildSelector(Interest::CHILD_RIGHT);
+
+ Ptr<Closure> closure = Ptr<Closure>(new Closure(boost::bind(&ContactPanel::onLocalPrefixVerified,
+ this,
+ _1),
+ boost::bind(&ContactPanel::onLocalPrefixTimeout,
+ this,
+ _1,
+ _2),
+ boost::bind(&ContactPanel::onLocalPrefixVerified,
+ this,
+ _1)));
+
+ m_handler->sendInterest(interest, closure);
+}
+
+void
+ContactPanel::onLocalPrefixVerified(Ptr<Data> data)
+{
+ string originPrefix(data->content().buf(), data->content().size());
+ string prefix = QString::fromStdString (originPrefix).trimmed ().toUtf8().constData();
+ string randomSuffix = getRandomString();
+ _LOG_DEBUG("prefix: " << prefix);
+ _LOG_DEBUG("randomSuffix: " << randomSuffix);
+ m_localPrefix = Name(prefix);
+}
+
+void
+ContactPanel::onLocalPrefixTimeout(Ptr<Closure> closure, Ptr<Interest> interest)
+{ throw LnException("No local prefix is found!"); }
+
+void
+ContactPanel::onUnverified(Ptr<Data> data)
+{}
+
+void
+ContactPanel::onTimeout(Ptr<Closure> closure, Ptr<Interest> interest)
+{}
+
+void
+ContactPanel::onInvitationCertVerified(Ptr<Data> data,
+ const Name& interestName,
+ int inviterIndex)
+{
+ Ptr<security::IdentityCertificate> certificate = Ptr<security::IdentityCertificate>(new security::IdentityCertificate(*data));
+
+ const int end = interestName.size();
+
+ string signature = interestName.get(end-1).toBlob();
+ Blob signatureBlob(signature.c_str(), signature.size());
+ string signedName = interestName.getSubName(0, end - 1).toUri();
+ Blob signedBlob(signedName.c_str(), signedName.size());
+
+ if(security::PolicyManager::verifySignature(signedBlob, signatureBlob, certificate->getPublicKeyInfo()))
+ {
+ Name keyName = certificate->getPublicKeyName();
+ Name inviterNameSpace = keyName.getSubName(0, keyName.size() - 1);
+ popChatInvitation(interestName, inviterIndex, inviterNameSpace, certificate);
+ }
+}
+
+void
+ContactPanel::popChatInvitation(const Name& interestName,
+ int inviterIndex,
+ const Name& inviterNameSpace,
+ Ptr<security::IdentityCertificate> certificate)
+{
+ string chatroomTag("chatroom");
+ int i = 0;
+ for(; i < inviterIndex; i++)
+ if(interestName.get(i).toUri() == chatroomTag)
+ break;
+ if(i+1 >= inviterIndex)
+ return;
+
+ string chatroom = interestName.get(i+1).toUri();
+ string inviter = inviterNameSpace.toUri();
+
+ m_invitationDialog->setMsg(inviter, chatroom);
+ m_invitationDialog->setIdentityCertificate(certificate);
+ m_invitationDialog->setInterestName(interestName);
+ m_invitationDialog->show();
+}
+
+static std::string chars("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789");
+
+string
+ContactPanel::getRandomString()
+{
+ string randStr;
+ boost::random::random_device rng;
+ boost::random::uniform_int_distribution<> index_dist(0, chars.size() - 1);
+ for (int i = 0; i < 10; i ++)
+ {
+ randStr += chars[index_dist(rng)];
+ }
+ return randStr;
+}
+
+
+void
+ContactPanel::setInvitationListener()
+{
+ Name prefix("/ndn/broadcast/chronos/invitation");
+ prefix.append(m_defaultIdentity);
+ m_handler->setInterestFilter (prefix,
+ boost::bind(&ContactPanel::onInvitation,
+ this,
+ _1));
+
+}
+
+void
+ContactPanel::onInvitation(Ptr<Interest> interest)
+{
+ const Name& interestName = interest->getName();
+ const int end = interestName.size();
+
+ string inviter("inviter");
+ int j = end-2;
+ for(; j >= 0; j--)
+ if(interestName.get(j).toUri() == inviter)
+ break;
+
+ //No certificate name found
+ if(j < 0)
+ return;
+
+ Name certName = interestName.getSubName(j+1, end-2-j);
+ string keyString("KEY");
+ string idString("ID-CERT");
+ int m = certName.size() - 1;
+ int keyIndex = -1;
+ int idIndex = -1;
+ for(; m >= 0; m--)
+ if(certName.get(m).toUri() == idString)
+ {
+ idIndex = m;
+ break;
+ }
+
+ for(; m >=0; m--)
+ if(certName.get(m).toUri() == keyString)
+ {
+ keyIndex = m;
+ break;
+ }
+
+ //Not a qualified certificate name
+ if(keyIndex < 0 && idIndex < 0)
+ return;
+
+ Ptr<Interest> newInterest = Ptr<Interest>(new Interest(certName));
+ Ptr<Closure> closure = Ptr<Closure>(new Closure(boost::bind(&ContactPanel::onInvitationCertVerified,
+ this,
+ _1,
+ interestName,
+ j),
+ boost::bind(&ContactPanel::onTimeout,
+ this,
+ _1,
+ _2),
+ boost::bind(&ContactPanel::onUnverified,
+ this,
+ _1)));
+ m_handler->sendInterest(newInterest, closure);
+}
+
+void
ContactPanel::updateSelection(const QItemSelection &selected,
const QItemSelection &deselected)
{
@@ -117,6 +349,10 @@
}
void
+ContactPanel::updateDefaultIdentity(const QString& identity)
+{ m_defaultIdentity = Name(identity.toUtf8().constData()); }
+
+void
ContactPanel::openProfileEditor()
{ m_profileEditor->show(); }
@@ -157,6 +393,13 @@
}
void
+ContactPanel::openSettingDialog()
+{
+ m_settingDialog->setIdentity(m_defaultIdentity.toUri());
+ m_settingDialog->show();
+}
+
+void
ContactPanel::openStartChatDialog()
{
TimeInterval ti = time::NowUnixTimestamp();
@@ -178,6 +421,32 @@
_LOG_DEBUG("introducer: " << std::boolalpha << isIntroducer);
}
+void
+ContactPanel::startChatroom2(const QString& chatroom, const QString& inviter)
+{
+ _LOG_DEBUG("room: " << chatroom.toUtf8().constData());
+ _LOG_DEBUG("inviter: " << inviter.toUtf8().constData());
+}
+
+void
+ContactPanel::acceptInvitation(const Name& interestName,
+ const security::IdentityCertificate& identityCertificate,
+ QString inviter,
+ QString chatroom)
+{
+ string prefix = m_localPrefix.toUri();
+ m_handler->publishDataByIdentity (interestName, prefix);
+ //TODO:: open chat dialog
+ startChatroom2(chatroom, inviter);
+}
+
+void
+ContactPanel::rejectInvitation(const ndn::Name& interestName)
+{
+ string empty;
+ m_handler->publishDataByIdentity (interestName, empty);
+}
+
#if WAF
#include "contactpanel.moc"