blob: 4ba732340a97ccc79d50b1e4e62e6d6391e48e57 [file] [log] [blame]
Yingdi Yu847aa862013-10-09 16:35:53 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013, Regents of the University of California
4 * Yingdi Yu
5 *
6 * BSD license, See the LICENSE file for more information
7 *
8 * Author: Yingdi Yu <yingdi@cs.ucla.edu>
9 */
10
11#include "contactpanel.h"
12#include "ui_contactpanel.h"
13
Yingdi Yu40eca752013-10-10 15:00:58 -070014
15#include <QStringList>
16#include <QItemSelectionModel>
17#include <QModelIndex>
Yingdi Yu3b318c12013-10-15 17:54:00 -070018#include <QDir>
Yingdi Yu40eca752013-10-10 15:00:58 -070019
Yingdi Yu3b318c12013-10-15 17:54:00 -070020#ifndef Q_MOC_RUN
Yingdi Yu978b3ae2013-10-23 11:50:51 -070021#include <ndn.cxx/security/keychain.h>
22#include <ndn.cxx/security/identity/osx-privatekey-storage.h>
23#include <ndn.cxx/security/identity/identity-manager.h>
24#include <ndn.cxx/security/identity/basic-identity-storage.h>
25#include <ndn.cxx/security/cache/ttl-certificate-cache.h>
26#include <ndn.cxx/security/encryption/basic-encryption-manager.h>
Yingdi Yu595aadc2013-10-21 15:01:40 -070027#include <ndn.cxx/common.h>
Yingdi Yu3b318c12013-10-15 17:54:00 -070028#include <boost/filesystem.hpp>
Yingdi Yu978b3ae2013-10-23 11:50:51 -070029#include <boost/random/random_device.hpp>
30#include <boost/random/uniform_int_distribution.hpp>
31#include "invitation-policy-manager.h"
Yingdi Yu3b318c12013-10-15 17:54:00 -070032#include "logging.h"
33#include "exception.h"
34#endif
35
36namespace fs = boost::filesystem;
37using namespace ndn;
Yingdi Yu978b3ae2013-10-23 11:50:51 -070038
Yingdi Yu2ac40fb2013-10-21 13:38:38 -070039using namespace std;
Yingdi Yu3b318c12013-10-15 17:54:00 -070040
41INIT_LOGGER("ContactPanel");
42
Yingdi Yu978b3ae2013-10-23 11:50:51 -070043Q_DECLARE_METATYPE(ndn::security::IdentityCertificate)
44
Yingdi Yu9236c432013-10-18 11:29:25 -070045ContactPanel::ContactPanel(Ptr<ContactManager> contactManager, QWidget *parent)
Yingdi Yu3b318c12013-10-15 17:54:00 -070046 : QDialog(parent)
47 , ui(new Ui::ContactPanel)
Yingdi Yu9236c432013-10-18 11:29:25 -070048 , m_contactManager(contactManager)
Yingdi Yu3b318c12013-10-15 17:54:00 -070049 , m_contactListModel(new QStringListModel)
Yingdi Yu978b3ae2013-10-23 11:50:51 -070050 , m_profileEditor(new ProfileEditor(m_contactManager))
Yingdi Yu9236c432013-10-18 11:29:25 -070051 , m_addContactPanel(new AddContactPanel(contactManager))
Yingdi Yu2ac40fb2013-10-21 13:38:38 -070052 , m_setAliasDialog(new SetAliasDialog(contactManager))
Yingdi Yu595aadc2013-10-21 15:01:40 -070053 , m_startChatDialog(new StartChatDialog)
Yingdi Yu978b3ae2013-10-23 11:50:51 -070054 , m_invitationDialog(new InvitationDialog)
55 , m_settingDialog(new SettingDialog)
Yingdi Yu595aadc2013-10-21 15:01:40 -070056 , m_menuInvite(new QAction("&Chat", this))
Yingdi Yu2ac40fb2013-10-21 13:38:38 -070057 , m_menuAlias(new QAction("&Set Alias", this))
Yingdi Yu847aa862013-10-09 16:35:53 -070058{
Yingdi Yu978b3ae2013-10-23 11:50:51 -070059 qRegisterMetaType<ndn::security::IdentityCertificate>("IdentityCertificate");
Yingdi Yu3b318c12013-10-15 17:54:00 -070060
Yingdi Yu978b3ae2013-10-23 11:50:51 -070061 ui->setupUi(this);
62 refreshContactList();
Yingdi Yu40eca752013-10-10 15:00:58 -070063
Yingdi Yu978b3ae2013-10-23 11:50:51 -070064 openDB();
Yingdi Yu3b318c12013-10-15 17:54:00 -070065
Yingdi Yu978b3ae2013-10-23 11:50:51 -070066 setKeychain();
67 m_handler = Ptr<Wrapper>(new Wrapper(m_keychain));
68
69 setLocalPrefix();
70
71 // Set Identity, TODO: through user interface
72 m_defaultIdentity = m_keychain->getDefaultIdentity();
73 m_settingDialog->setIdentity(m_defaultIdentity.toUri());
74 setInvitationListener();
Yingdi Yu8f7325a2013-10-17 17:03:46 -070075
Yingdi Yu978b3ae2013-10-23 11:50:51 -070076 ui->ContactList->setModel(m_contactListModel);
Yingdi Yu40eca752013-10-10 15:00:58 -070077
Yingdi Yu978b3ae2013-10-23 11:50:51 -070078 QItemSelectionModel* selectionModel = ui->ContactList->selectionModel();
Yingdi Yu0269c872013-10-16 13:16:49 -070079
Yingdi Yu978b3ae2013-10-23 11:50:51 -070080 connect(selectionModel, SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)),
81 this, SLOT(updateSelection(const QItemSelection &, const QItemSelection &)));
Yingdi Yu0269c872013-10-16 13:16:49 -070082
Yingdi Yu978b3ae2013-10-23 11:50:51 -070083 connect(ui->ContactList, SIGNAL(customContextMenuRequested(const QPoint&)),
84 this, SLOT(showContextMenu(const QPoint&)));
Yingdi Yu2ac40fb2013-10-21 13:38:38 -070085
Yingdi Yu978b3ae2013-10-23 11:50:51 -070086 connect(ui->EditProfileButton, SIGNAL(clicked()),
87 this, SLOT(openProfileEditor()));
Yingdi Yu2ac40fb2013-10-21 13:38:38 -070088
Yingdi Yu978b3ae2013-10-23 11:50:51 -070089 connect(ui->AddContactButton, SIGNAL(clicked()),
90 this, SLOT(openAddContactPanel()));
91
92 connect(ui->settingButton, SIGNAL(clicked()),
93 this, SLOT(openSettingDialog()));
94
95 connect(m_addContactPanel, SIGNAL(newContactAdded()),
96 this, SLOT(refreshContactList()));
97
98 connect(m_setAliasDialog, SIGNAL(aliasChanged()),
99 this, SLOT(refreshContactList()));
100
101 connect(m_startChatDialog, SIGNAL(chatroomConfirmed(const QString&, const QString&, bool)),
102 this, SLOT(startChatroom(const QString&, const QString&, bool)));
103
104 connect(m_invitationDialog, SIGNAL(invitationAccepted(const ndn::Name&, const ndn::security::IdentityCertificate&, QString, QString)),
105 this, SLOT(acceptInvitation(const ndn::Name&, const ndn::security::IdentityCertificate&, QString, QString)));
106 connect(m_invitationDialog, SIGNAL(invitationRejected(const ndn::Name&)),
107 this, SLOT(rejectInvitation(const ndn::Name&)));
108
109 connect(m_settingDialog, SIGNAL(identitySet(const QString&)),
110 this, SLOT(updateDefaultIdentity(const QString&)));
Yingdi Yu595aadc2013-10-21 15:01:40 -0700111
Yingdi Yu2ac40fb2013-10-21 13:38:38 -0700112
113
Yingdi Yu847aa862013-10-09 16:35:53 -0700114}
115
116ContactPanel::~ContactPanel()
117{
118 delete ui;
Yingdi Yu40eca752013-10-10 15:00:58 -0700119 delete m_contactListModel;
Yingdi Yu0269c872013-10-16 13:16:49 -0700120 delete m_profileEditor;
121 delete m_addContactPanel;
Yingdi Yu2ac40fb2013-10-21 13:38:38 -0700122
123 delete m_menuInvite;
Yingdi Yu847aa862013-10-09 16:35:53 -0700124}
125
Yingdi Yu40eca752013-10-10 15:00:58 -0700126void
Yingdi Yu978b3ae2013-10-23 11:50:51 -0700127ContactPanel::openDB()
128{
129 QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
130 QString path = (QDir::home().path());
131 path.append(QDir::separator()).append(".chronos").append(QDir::separator()).append("chronos.db");
132 db.setDatabaseName(path);
133 bool ok = db.open();
134}
135
136void
137ContactPanel::setKeychain()
138{
139 Ptr<security::OSXPrivatekeyStorage> privateStorage = Ptr<security::OSXPrivatekeyStorage>::Create();
140 Ptr<security::IdentityManager> identityManager = Ptr<security::IdentityManager>(new security::IdentityManager(Ptr<security::BasicIdentityStorage>::Create(), privateStorage));
141 Ptr<security::CertificateCache> certificateCache = Ptr<security::CertificateCache>(new security::TTLCertificateCache());
142 Ptr<InvitationPolicyManager> policyManager = Ptr<InvitationPolicyManager>(new InvitationPolicyManager(10, certificateCache));
143 Ptr<security::EncryptionManager> encryptionManager = Ptr<security::EncryptionManager>(new security::BasicEncryptionManager(privateStorage, "/tmp/encryption.db"));
144
145 vector<Ptr<ContactItem> >::const_iterator it = m_contactList.begin();
146 for(; it != m_contactList.end(); it++)
147 policyManager->addTrustAnchor((*it)->getSelfEndorseCertificate());
148
149 m_keychain = Ptr<security::Keychain>(new security::Keychain(identityManager, policyManager, encryptionManager));
150}
151
152void
153ContactPanel::setLocalPrefix()
154{
155 Ptr<Interest> interest = Ptr<Interest>(new Interest(Name("/local/ndn/prefix")));
156 interest->setChildSelector(Interest::CHILD_RIGHT);
157
158 Ptr<Closure> closure = Ptr<Closure>(new Closure(boost::bind(&ContactPanel::onLocalPrefixVerified,
159 this,
160 _1),
161 boost::bind(&ContactPanel::onLocalPrefixTimeout,
162 this,
163 _1,
164 _2),
165 boost::bind(&ContactPanel::onLocalPrefixVerified,
166 this,
167 _1)));
168
169 m_handler->sendInterest(interest, closure);
170}
171
172void
173ContactPanel::onLocalPrefixVerified(Ptr<Data> data)
174{
175 string originPrefix(data->content().buf(), data->content().size());
176 string prefix = QString::fromStdString (originPrefix).trimmed ().toUtf8().constData();
177 string randomSuffix = getRandomString();
178 _LOG_DEBUG("prefix: " << prefix);
179 _LOG_DEBUG("randomSuffix: " << randomSuffix);
180 m_localPrefix = Name(prefix);
181}
182
183void
184ContactPanel::onLocalPrefixTimeout(Ptr<Closure> closure, Ptr<Interest> interest)
185{ throw LnException("No local prefix is found!"); }
186
187void
188ContactPanel::onUnverified(Ptr<Data> data)
189{}
190
191void
192ContactPanel::onTimeout(Ptr<Closure> closure, Ptr<Interest> interest)
193{}
194
195void
196ContactPanel::onInvitationCertVerified(Ptr<Data> data,
197 const Name& interestName,
198 int inviterIndex)
199{
200 Ptr<security::IdentityCertificate> certificate = Ptr<security::IdentityCertificate>(new security::IdentityCertificate(*data));
201
202 const int end = interestName.size();
203
204 string signature = interestName.get(end-1).toBlob();
205 Blob signatureBlob(signature.c_str(), signature.size());
206 string signedName = interestName.getSubName(0, end - 1).toUri();
207 Blob signedBlob(signedName.c_str(), signedName.size());
208
209 if(security::PolicyManager::verifySignature(signedBlob, signatureBlob, certificate->getPublicKeyInfo()))
210 {
211 Name keyName = certificate->getPublicKeyName();
212 Name inviterNameSpace = keyName.getSubName(0, keyName.size() - 1);
213 popChatInvitation(interestName, inviterIndex, inviterNameSpace, certificate);
214 }
215}
216
217void
218ContactPanel::popChatInvitation(const Name& interestName,
219 int inviterIndex,
220 const Name& inviterNameSpace,
221 Ptr<security::IdentityCertificate> certificate)
222{
223 string chatroomTag("chatroom");
224 int i = 0;
225 for(; i < inviterIndex; i++)
226 if(interestName.get(i).toUri() == chatroomTag)
227 break;
228 if(i+1 >= inviterIndex)
229 return;
230
231 string chatroom = interestName.get(i+1).toUri();
232 string inviter = inviterNameSpace.toUri();
233
234 m_invitationDialog->setMsg(inviter, chatroom);
235 m_invitationDialog->setIdentityCertificate(certificate);
236 m_invitationDialog->setInterestName(interestName);
237 m_invitationDialog->show();
238}
239
240static std::string chars("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM0123456789");
241
242string
243ContactPanel::getRandomString()
244{
245 string randStr;
246 boost::random::random_device rng;
247 boost::random::uniform_int_distribution<> index_dist(0, chars.size() - 1);
248 for (int i = 0; i < 10; i ++)
249 {
250 randStr += chars[index_dist(rng)];
251 }
252 return randStr;
253}
254
255
256void
257ContactPanel::setInvitationListener()
258{
259 Name prefix("/ndn/broadcast/chronos/invitation");
260 prefix.append(m_defaultIdentity);
261 m_handler->setInterestFilter (prefix,
262 boost::bind(&ContactPanel::onInvitation,
263 this,
264 _1));
265
266}
267
268void
269ContactPanel::onInvitation(Ptr<Interest> interest)
270{
271 const Name& interestName = interest->getName();
272 const int end = interestName.size();
273
274 string inviter("inviter");
275 int j = end-2;
276 for(; j >= 0; j--)
277 if(interestName.get(j).toUri() == inviter)
278 break;
279
280 //No certificate name found
281 if(j < 0)
282 return;
283
284 Name certName = interestName.getSubName(j+1, end-2-j);
285 string keyString("KEY");
286 string idString("ID-CERT");
287 int m = certName.size() - 1;
288 int keyIndex = -1;
289 int idIndex = -1;
290 for(; m >= 0; m--)
291 if(certName.get(m).toUri() == idString)
292 {
293 idIndex = m;
294 break;
295 }
296
297 for(; m >=0; m--)
298 if(certName.get(m).toUri() == keyString)
299 {
300 keyIndex = m;
301 break;
302 }
303
304 //Not a qualified certificate name
305 if(keyIndex < 0 && idIndex < 0)
306 return;
307
308 Ptr<Interest> newInterest = Ptr<Interest>(new Interest(certName));
309 Ptr<Closure> closure = Ptr<Closure>(new Closure(boost::bind(&ContactPanel::onInvitationCertVerified,
310 this,
311 _1,
312 interestName,
313 j),
314 boost::bind(&ContactPanel::onTimeout,
315 this,
316 _1,
317 _2),
318 boost::bind(&ContactPanel::onUnverified,
319 this,
320 _1)));
321 m_handler->sendInterest(newInterest, closure);
322}
323
324void
Yingdi Yu40eca752013-10-10 15:00:58 -0700325ContactPanel::updateSelection(const QItemSelection &selected,
326 const QItemSelection &deselected)
327{
328 QModelIndexList items = selected.indexes();
329 QString text = m_contactListModel->data(items.first(), Qt::DisplayRole).toString();
Yingdi Yu2ac40fb2013-10-21 13:38:38 -0700330 string alias = text.toUtf8().constData();
331
Yingdi Yu2ac40fb2013-10-21 13:38:38 -0700332 int i = 0;
333 for(; i < m_contactList.size(); i++)
334 {
335 if(alias == m_contactList[i]->getAlias())
336 break;
337 }
338
339 QString name = QString::fromUtf8(m_contactList[i]->getName().c_str());
340 QString institution = QString::fromUtf8(m_contactList[i]->getInstitution().c_str());
341 QString nameSpace = QString::fromUtf8(m_contactList[i]->getNameSpace().toUri().c_str());
342 ui->NameData->setText(name);
343 ui->NameSpaceData->setText(nameSpace);
344 ui->InstitutionData->setText(institution);
Yingdi Yu595aadc2013-10-21 15:01:40 -0700345
346 m_currentSelectedContactAlias = alias;
347 m_currentSelectedContactNamespace = m_contactList[i]->getNameSpace().toUri();
Yingdi Yu2ac40fb2013-10-21 13:38:38 -0700348 // _LOG_DEBUG("current Alias: " << m_currentSelectedContact);
Yingdi Yu40eca752013-10-10 15:00:58 -0700349}
Yingdi Yu847aa862013-10-09 16:35:53 -0700350
Yingdi Yu3b318c12013-10-15 17:54:00 -0700351void
Yingdi Yu978b3ae2013-10-23 11:50:51 -0700352ContactPanel::updateDefaultIdentity(const QString& identity)
353{ m_defaultIdentity = Name(identity.toUtf8().constData()); }
354
355void
Yingdi Yu3b318c12013-10-15 17:54:00 -0700356ContactPanel::openProfileEditor()
Yingdi Yu0269c872013-10-16 13:16:49 -0700357{ m_profileEditor->show(); }
Yingdi Yu3b318c12013-10-15 17:54:00 -0700358
Yingdi Yu0269c872013-10-16 13:16:49 -0700359void
360ContactPanel::openAddContactPanel()
361{ m_addContactPanel->show(); }
Yingdi Yu3b318c12013-10-15 17:54:00 -0700362
Yingdi Yu2ac40fb2013-10-21 13:38:38 -0700363void
364ContactPanel::refreshContactList()
365{
366 m_contactList = m_contactManager->getContactItemList();
367 QStringList contactNameList;
368 for(int i = 0; i < m_contactList.size(); i++)
369 contactNameList << QString::fromUtf8(m_contactList[i]->getAlias().c_str());
370
371 m_contactListModel->setStringList(contactNameList);
372}
373
374void
375ContactPanel::showContextMenu(const QPoint& pos)
376{
377 QMenu menu(ui->ContactList);
378 menu.addAction(m_menuInvite);
Yingdi Yu595aadc2013-10-21 15:01:40 -0700379 connect(m_menuInvite, SIGNAL(triggered()),
380 this, SLOT(openStartChatDialog()));
Yingdi Yu2ac40fb2013-10-21 13:38:38 -0700381 menu.addAction(m_menuAlias);
382 connect(m_menuAlias, SIGNAL(triggered()),
383 this, SLOT(openSetAliasDialog()));
384 menu.exec(ui->ContactList->mapToGlobal(pos));
385
386}
387
388void
389ContactPanel::openSetAliasDialog()
390{
Yingdi Yu595aadc2013-10-21 15:01:40 -0700391 m_setAliasDialog->setTargetIdentity(m_currentSelectedContactNamespace);
Yingdi Yu2ac40fb2013-10-21 13:38:38 -0700392 m_setAliasDialog->show();
393}
394
Yingdi Yu595aadc2013-10-21 15:01:40 -0700395void
Yingdi Yu978b3ae2013-10-23 11:50:51 -0700396ContactPanel::openSettingDialog()
397{
398 m_settingDialog->setIdentity(m_defaultIdentity.toUri());
399 m_settingDialog->show();
400}
401
402void
Yingdi Yu595aadc2013-10-21 15:01:40 -0700403ContactPanel::openStartChatDialog()
404{
405 TimeInterval ti = time::NowUnixTimestamp();
406 ostringstream oss;
407 oss << ti.total_seconds();
408
409 Name chatroom("/ndn/broadcast/chronos");
410 chatroom.append(string("chatroom-") + oss.str());
411
412 m_startChatDialog->setInvitee(m_currentSelectedContactNamespace, chatroom.toUri());
413 m_startChatDialog->show();
414}
415
416void
417ContactPanel::startChatroom(const QString& chatroom, const QString& invitee, bool isIntroducer)
418{
419 _LOG_DEBUG("room: " << chatroom.toUtf8().constData());
420 _LOG_DEBUG("invitee: " << invitee.toUtf8().constData());
421 _LOG_DEBUG("introducer: " << std::boolalpha << isIntroducer);
422}
423
Yingdi Yu978b3ae2013-10-23 11:50:51 -0700424void
425ContactPanel::startChatroom2(const QString& chatroom, const QString& inviter)
426{
427 _LOG_DEBUG("room: " << chatroom.toUtf8().constData());
428 _LOG_DEBUG("inviter: " << inviter.toUtf8().constData());
429}
430
431void
432ContactPanel::acceptInvitation(const Name& interestName,
433 const security::IdentityCertificate& identityCertificate,
434 QString inviter,
435 QString chatroom)
436{
437 string prefix = m_localPrefix.toUri();
438 m_handler->publishDataByIdentity (interestName, prefix);
439 //TODO:: open chat dialog
440 startChatroom2(chatroom, inviter);
441}
442
443void
444ContactPanel::rejectInvitation(const ndn::Name& interestName)
445{
446 string empty;
447 m_handler->publishDataByIdentity (interestName, empty);
448}
449
Yingdi Yu595aadc2013-10-21 15:01:40 -0700450
Yingdi Yu847aa862013-10-09 16:35:53 -0700451#if WAF
452#include "contactpanel.moc"
453#include "contactpanel.cpp.moc"
454#endif