diff --git a/lib/ucoinpy/documents/certification.py b/lib/ucoinpy/documents/certification.py index 3d75840978a2d93ca73224c7dfc0a95a7bab8ac1..10a9cb5ec5cd24043e4369ea824ee02628a7a775 100644 --- a/lib/ucoinpy/documents/certification.py +++ b/lib/ucoinpy/documents/certification.py @@ -37,7 +37,8 @@ class SelfCertification(Document): def raw(self): return """UID:{0} -META:TS:{1}""".format(self.uid(), self.ts()) +META:TS:{1} +""".format(self.uid, self.timestamp) def inline(self): return "{0}:{1}:{2}:{3}".format(self.pubkey, self.signatures[0], @@ -77,8 +78,16 @@ class Certification(Document): blockhash, blocknumber, signature) def raw(self, selfcert): - return """{0} -META:TS:{1}-{2}""".format(selfcert.signed_raw(), self.blockhash, self.blocknumber) + return """{0}META:TS:{1}-{2} +""".format(selfcert.signed_raw(), self.blockhash, self.blocknumber) + + def signed_raw(self, selfcert): + raw = self.raw(selfcert) + signed_raw = raw + for s in self.signatures: + if s is not None: + signed_raw += s + "\n" + return signed_raw def inline(self): return "{0}:{1}:{2}:{3}".format(self.pubkey_from, self.pubkey_to, diff --git a/res/ui/mainwindow.ui b/res/ui/mainwindow.ui index 6ff91b45dc44af3643945b8f052da8f841ccd464..47fd6e376b57680e2e61ff9bdd0ae5c609bb5be3 100644 --- a/res/ui/mainwindow.ui +++ b/res/ui/mainwindow.ui @@ -73,6 +73,7 @@ <string>Actions</string> </property> <addaction name="actionTransfer_money"/> + <addaction name="actionCertification"/> </widget> <addaction name="menu_account"/> <addaction name="menu_contacts"/> @@ -164,6 +165,11 @@ <string>Export</string> </property> </action> + <action name="actionCertification"> + <property name="text"> + <string>Certification</string> + </property> + </action> </widget> <resources/> <connections> @@ -279,6 +285,22 @@ </hint> </hints> </connection> + <connection> + <sender>actionCertification</sender> + <signal>triggered()</signal> + <receiver>MainWindow</receiver> + <slot>open_certification_dialog()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>248</x> + <y>218</y> + </hint> + </hints> + </connection> </connections> <slots> <slot>open_add_account_dialog()</slot> @@ -289,5 +311,6 @@ <slot>refresh_main_window()</slot> <slot>refresh_wallet_content(QModelIndex)</slot> <slot>export_account()</slot> + <slot>open_certification_dialog()</slot> </slots> </ui> diff --git a/src/cutecoin/core/account.py b/src/cutecoin/core/account.py index fdbd26648bdd4b69192168b7c10a337df6c63c7c..f36419a741c30e55fc3ae5faefe16efe90307f45 100644 --- a/src/cutecoin/core/account.py +++ b/src/cutecoin/core/account.py @@ -4,10 +4,17 @@ Created on 1 févr. 2014 @author: inso ''' +from ucoinpy import PROTOCOL_VERSION from ucoinpy.api import bma from ucoinpy.api.bma import ConnectionHandler from ucoinpy.documents.peer import Peer +from ucoinpy.documents.certification import Certification +from ucoinpy.key import SigningKey + import logging +import hashlib +import base64 + from .wallet import Wallet from .community import Community from .person import Person @@ -68,6 +75,10 @@ class Account(object): else: return False + def check_password(self, password): + key = SigningKey(self.salt, password) + return (key.pubkey == self.pubkey) + def add_contact(self, person): self.contacts.append(person) @@ -99,6 +110,31 @@ class Account(object): wid = w.walletid + 1 return wid + def certify(self, password, community, pubkey): + certified = Person.lookup(pubkey, community) + block = community.get_block() + block_hash = hashlib.sha1(block.signed_raw().encode("ascii")).hexdigest().upper() + + certification = Certification(PROTOCOL_VERSION, community.currency, + self.pubkey, certified.pubkey, + block.number, block_hash, None) + + selfcert = certified.selfcert(community) + raw_cert = certification.raw(selfcert) + logging.debug("SelfCertification : {0}".format(selfcert.raw())) + + key = SigningKey(self.salt, password) + signing = base64.b64encode(key.signature(bytes(raw_cert, 'ascii'))) + logging.debug("Signature : {0}".format(signing.decode("ascii"))) + certification.signatures = [signing.decode("ascii")] + signed_cert = certification.signed_raw(selfcert) + logging.debug("Certification : {0}".format(signed_cert)) + + community.post(bma.wot.Add, {}, + {'pubkey': certified.pubkey, + 'self': selfcert.signed_raw(), + 'others': certification.inline() + "\n"}) + def sources(self, community): sources = [] for w in self.wallets: diff --git a/src/cutecoin/core/community.py b/src/cutecoin/core/community.py index 5138b40576df28cf5b0c6603f6ec6cab105bb268..c060f1adca84588bcbb83efe9e1a2e920f2f01e4 100644 --- a/src/cutecoin/core/community.py +++ b/src/cutecoin/core/community.py @@ -145,6 +145,7 @@ class Community(object): e = next(e for e in peer.endpoints if type(e) is BMAEndpoint) logging.debug("Trying to connect to : " + peer.pubkey) req = request(e.conn_handler(), **req_args) + logging.debug("{0}".format(post_args)) req.post(**post_args) def jsonify_peers_list(self): diff --git a/src/cutecoin/core/person.py b/src/cutecoin/core/person.py index 0c2dc519d95ed108164f9050a1ad8793b1f76a8e..bb4920c3850908910e14fb2a87f93a2f892ab51d 100644 --- a/src/cutecoin/core/person.py +++ b/src/cutecoin/core/person.py @@ -6,6 +6,8 @@ Created on 11 févr. 2014 import logging from ucoinpy.api import bma +from ucoinpy import PROTOCOL_VERSION +from ucoinpy.documents.certification import SelfCertification from cutecoin.tools.exceptions import PersonNotFoundError @@ -31,17 +33,18 @@ class Person(object): data = community.request(bma.wot.Lookup, req_args={'search': pubkey}) logging.debug(data) results = data['results'] - if len(results) > 0: - uids = results[0]['uids'] - if len(uids) > 0: - name = uids[0]["uid"] - else: - raise PersonNotFoundError(pubkey, community.name()) - return None - else: - raise PersonNotFoundError(pubkey, community.name()) - return None - return cls(name, pubkey) + timestamp = 0 + + for result in data['results']: + if result["pubkey"] == pubkey: + uids = result['uids'] + for uid in uids: + if uid["meta"]["timestamp"] > timestamp: + timestamp = uid["meta"]["timestamp"] + name = uid["uid"] + + return cls(name, pubkey) + raise PersonNotFoundError(pubkey, community.name()) @classmethod def from_json(cls, json_person): @@ -52,6 +55,28 @@ class Person(object): pubkey = json_person['pubkey'] return cls(name, pubkey) + def selfcert(self, community): + data = community.request(bma.wot.Lookup, req_args={'search': self.pubkey}) + logging.debug(data) + timestamp = 0 + + for result in data['results']: + if result["pubkey"] == self.pubkey: + uids = result['uids'] + for uid in uids: + if uid["meta"]["timestamp"] > timestamp: + timestamp = uid["meta"]["timestamp"] + name = uid["uid"] + signature = uid["self"] + + return SelfCertification(PROTOCOL_VERSION, + community.currency, + self.pubkey, + timestamp, + name, + signature) + raise PersonNotFoundError(self.pubkey, community.name()) + def jsonify(self): data = {'name': self.name, 'pubkey': self.pubkey} diff --git a/src/cutecoin/gui/mainwindow.py b/src/cutecoin/gui/mainwindow.py index 46ba336e93ffa5f654cace9ca7be11306aaf9fb6..d41a105579fe7d5b7b29305a06b5d5f4cf577921 100644 --- a/src/cutecoin/gui/mainwindow.py +++ b/src/cutecoin/gui/mainwindow.py @@ -11,6 +11,8 @@ from cutecoin.gui.transfer import TransferMoneyDialog from cutecoin.gui.currency_tab import CurrencyTabWidget from cutecoin.gui.add_contact import AddContactDialog from cutecoin.gui.import_account import ImportAccountDialog +from cutecoin.gui.certification import CertificationDialog + import logging @@ -45,6 +47,10 @@ class MainWindow(QMainWindow, Ui_MainWindow): dialog.accepted.connect(self.refresh_wallets) dialog.exec_() + def open_certification_dialog(self): + dialog = CertificationDialog(self.app.current_account) + dialog.exec_() + def open_add_contact_dialog(self): AddContactDialog(self.app.current_account, self).exec_()