From 6f34f0bb6bf15e3d2b248ae4685c139fda2fddba Mon Sep 17 00:00:00 2001 From: Inso <insomniak.fr@gmail.com> Date: Fri, 26 Dec 2014 08:37:24 +0100 Subject: [PATCH] Signing is now available ! --- lib/ucoinpy/api/bma/__init__.py | 2 +- lib/ucoinpy/documents/__init__.py | 19 ++- lib/ucoinpy/documents/block.py | 5 +- lib/ucoinpy/documents/certification.py | 26 +++- lib/ucoinpy/documents/membership.py | 5 +- lib/ucoinpy/documents/peer.py | 5 +- lib/ucoinpy/documents/status.py | 5 +- lib/ucoinpy/documents/transaction.py | 7 +- res/ui/certification.ui | 177 +++++++++++++++++++++++++ src/cutecoin/core/account.py | 6 +- src/cutecoin/core/wallet.py | 4 +- src/cutecoin/gui/certification.py | 76 +++++++++++ src/cutecoin/gui/views/__init__.py | 0 13 files changed, 295 insertions(+), 42 deletions(-) create mode 100644 res/ui/certification.ui create mode 100644 src/cutecoin/gui/certification.py create mode 100644 src/cutecoin/gui/views/__init__.py diff --git a/lib/ucoinpy/api/bma/__init__.py b/lib/ucoinpy/api/bma/__init__.py index 57e861a7..02fac8a9 100644 --- a/lib/ucoinpy/api/bma/__init__.py +++ b/lib/ucoinpy/api/bma/__init__.py @@ -123,7 +123,7 @@ class API(object): Arguments: - `path`: the request path """ - if 'self_' in kwargs.keys(): + if 'self_' in kwargs: kwargs['self'] = kwargs.pop('self_') logging.debug("POST : {0}".format(kwargs)) diff --git a/lib/ucoinpy/documents/__init__.py b/lib/ucoinpy/documents/__init__.py index 54b24ddc..198b62b4 100644 --- a/lib/ucoinpy/documents/__init__.py +++ b/lib/ucoinpy/documents/__init__.py @@ -4,7 +4,9 @@ Created on 3 déc. 2014 @author: inso ''' import base58 +import base64 import re +import logging from ..key import Base58Encoder class Document: @@ -15,7 +17,10 @@ class Document: def __init__(self, version, currency, signatures): self.version = version self.currency = currency - self.signatures = signatures + if signatures: + self.signatures = [s for s in signatures if s is not None] + else: + self.signatures = [] def sign(self, keys): ''' @@ -23,8 +28,10 @@ class Document: Warning : current signatures will be replaced with the new ones. ''' self.signatures = [] - for k in keys: - self.signatures.append(k.signature(self.raw())) + for key in keys: + signing = base64.b64encode(key.signature(bytes(self.raw(), 'ascii'))) + logging.debug("Signature : \n{0}".format(signing.decode("ascii"))) + self.signatures.append(signing.decode("ascii")) def signed_raw(self): ''' @@ -32,8 +39,6 @@ class Document: If keys are present, returns the raw signed by these keys ''' raw = self.raw() - signed_raw = raw - for s in self.signatures: - if s is not None: - signed_raw += s + "\n" + signed = "\n".join(self.signatures) + signed_raw = raw + signed + "\n" return signed_raw diff --git a/lib/ucoinpy/documents/block.py b/lib/ucoinpy/documents/block.py index 1bf08afe..031c69f1 100644 --- a/lib/ucoinpy/documents/block.py +++ b/lib/ucoinpy/documents/block.py @@ -83,10 +83,7 @@ BOTTOM_SIGNATURE ''' Constructor ''' - if signature: - super().__init__(version, currency, [signature]) - else: - super().__init__(version, currency, []) + super().__init__(version, currency, [signature]) self.noonce = noonce self.number = number self.powmin = powmin diff --git a/lib/ucoinpy/documents/certification.py b/lib/ucoinpy/documents/certification.py index 03898313..582e2625 100644 --- a/lib/ucoinpy/documents/certification.py +++ b/lib/ucoinpy/documents/certification.py @@ -4,6 +4,8 @@ Created on 2 déc. 2014 @author: inso ''' import re +import base64 +import logging from . import Document @@ -40,6 +42,9 @@ class SelfCertification(Document): META:TS:{1} """.format(self.uid, self.timestamp) + def signed_raw(self): + return super().signed_raw()[:-1] + def inline(self): return "{0}:{1}:{2}:{3}".format(self.pubkey, self.signatures[0], self.timestamp, self.uid) @@ -78,15 +83,26 @@ class Certification(Document): blockhash, blocknumber, signature) def raw(self, selfcert): - return """{0}META:TS:{1}-{2} + return """{0} +META:TS:{1}-{2} """.format(selfcert.signed_raw(), self.blocknumber, self.blockhash) + + def sign(self, selfcert, keys): + ''' + Sign the current document. + Warning : current signatures will be replaced with the new ones. + ''' + self.signatures = [] + for key in keys: + signing = base64.b64encode(key.signature(bytes(self.raw(selfcert), 'ascii'))) + logging.debug("Signature : \n{0}".format(signing.decode("ascii"))) + self.signatures.append(signing.decode("ascii")) + 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" + signed = "\n".join(self.signatures) + signed_raw = raw + signed + "\n" return signed_raw def inline(self): diff --git a/lib/ucoinpy/documents/membership.py b/lib/ucoinpy/documents/membership.py index 3f142a7f..af71a3a0 100644 --- a/lib/ucoinpy/documents/membership.py +++ b/lib/ucoinpy/documents/membership.py @@ -39,10 +39,7 @@ class Membership(Document): ''' Constructor ''' - if signature: - super().__init__(version, currency, [signature]) - else: - super().__init__(version, currency, []) + super().__init__(version, currency, [signature]) self.issuer = issuer self.block_number = block_number self.block_hash = block_hash diff --git a/lib/ucoinpy/documents/peer.py b/lib/ucoinpy/documents/peer.py index 128da67b..6b437a6d 100644 --- a/lib/ucoinpy/documents/peer.py +++ b/lib/ucoinpy/documents/peer.py @@ -32,10 +32,7 @@ class Peer(Document): def __init__(self, version, currency, pubkey, blockid, endpoints, signature): - if signature: - super().__init__(version, currency, [signature]) - else: - super().__init__(version, currency, []) + super().__init__(version, currency, [signature]) self.pubkey = pubkey self.blockid = blockid diff --git a/lib/ucoinpy/documents/status.py b/lib/ucoinpy/documents/status.py index 5b25bfae..2ba47ea8 100644 --- a/lib/ucoinpy/documents/status.py +++ b/lib/ucoinpy/documents/status.py @@ -30,10 +30,7 @@ class Status(Document): ''' Constructor ''' - if signature: - super().__init__(version, currency, [signature]) - else: - super().__init__(version, currency, []) + super().__init__(version, currency, [signature]) self.status = status self.blockid = blockid diff --git a/lib/ucoinpy/documents/transaction.py b/lib/ucoinpy/documents/transaction.py index ce7d84a0..24989c06 100644 --- a/lib/ucoinpy/documents/transaction.py +++ b/lib/ucoinpy/documents/transaction.py @@ -54,10 +54,7 @@ SIGNATURE ''' Constructor ''' - if signatures: - super().__init__(version, currency, signatures) - else: - super().__init__(version, currency, []) + super().__init__(version, currency, signatures) self.issuers = issuers self.inputs = inputs @@ -80,7 +77,7 @@ SIGNATURE inputs = [] outputs = [] signatures = [] - + logging.debug(compact) for i in range(0, issuers_num): issuer = Transaction.re_pubkey.match(lines[n]).group(1) issuers.append(issuer) diff --git a/res/ui/certification.ui b/res/ui/certification.ui new file mode 100644 index 00000000..fda8aba4 --- /dev/null +++ b/res/ui/certification.ui @@ -0,0 +1,177 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>CertificationDialog</class> + <widget class="QDialog" name="CertificationDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>399</width> + <height>216</height> + </rect> + </property> + <property name="windowTitle"> + <string>Certification</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QGroupBox" name="groupBox_2"> + <property name="title"> + <string>Community</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="QComboBox" name="combo_community"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Certify user</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QRadioButton" name="radio_contact"> + <property name="text"> + <string>Contact</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="combo_contact"> + <property name="enabled"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QRadioButton" name="radio_pubkey"> + <property name="text"> + <string>User public key</string> + </property> + <property name="checked"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="edit_pubkey"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="inputMask"> + <string/> + </property> + <property name="text"> + <string/> + </property> + <property name="placeholderText"> + <string>Key</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="button_box"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>button_box</sender> + <signal>accepted()</signal> + <receiver>CertificationDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>button_box</sender> + <signal>rejected()</signal> + <receiver>CertificationDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>radio_pubkey</sender> + <signal>toggled(bool)</signal> + <receiver>CertificationDialog</receiver> + <slot>recipient_mode_changed(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>87</x> + <y>51</y> + </hint> + <hint type="destinationlabel"> + <x>199</x> + <y>244</y> + </hint> + </hints> + </connection> + <connection> + <sender>combo_community</sender> + <signal>currentIndexChanged(int)</signal> + <receiver>CertificationDialog</receiver> + <slot>change_current_community(int)</slot> + <hints> + <hint type="sourcelabel"> + <x>199</x> + <y>50</y> + </hint> + <hint type="destinationlabel"> + <x>199</x> + <y>165</y> + </hint> + </hints> + </connection> + </connections> + <slots> + <slot>open_manage_wallet_coins()</slot> + <slot>change_displayed_wallet(int)</slot> + <slot>transfer_mode_changed(bool)</slot> + <slot>recipient_mode_changed(bool)</slot> + <slot>change_current_community(int)</slot> + <slot>amount_changed()</slot> + <slot>relative_amount_changed()</slot> + </slots> +</ui> diff --git a/src/cutecoin/core/account.py b/src/cutecoin/core/account.py index 45c675ac..426ce09f 100644 --- a/src/cutecoin/core/account.py +++ b/src/cutecoin/core/account.py @@ -120,14 +120,10 @@ class Account(object): block_hash, block.number, 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("Raw certification {0}".format(raw_cert)) - logging.debug("Signature of {0}".format(signing.decode("ascii"))) - certification.signatures = [signing.decode("ascii")] + certification.sign(selfcert, [key]) signed_cert = certification.signed_raw(selfcert) logging.debug("Certification : {0}".format(signed_cert)) diff --git a/src/cutecoin/core/wallet.py b/src/cutecoin/core/wallet.py index f833d2e6..a1c032a0 100644 --- a/src/cutecoin/core/wallet.py +++ b/src/cutecoin/core/wallet.py @@ -116,9 +116,7 @@ class Wallet(object): key = SigningKey("{0}{1}".format(salt, self.walletid), password) logging.debug("Sender pubkey:{0}".format(key.pubkey)) - signing = base64.b64encode(key.signature(bytes(tx.raw(), 'ascii'))) - logging.debug("Signature : {0}".format(signing.decode("ascii"))) - tx.signatures = [signing.decode("ascii")] + tx.sign([key]) logging.debug("Transaction : {0}".format(tx.signed_raw())) community.post(bma.tx.Process, post_args={'transaction': tx.signed_raw()}) diff --git a/src/cutecoin/gui/certification.py b/src/cutecoin/gui/certification.py new file mode 100644 index 00000000..d31c00ff --- /dev/null +++ b/src/cutecoin/gui/certification.py @@ -0,0 +1,76 @@ +''' +Created on 24 dec. 2014 + +@author: inso +''' +from PyQt5.QtWidgets import QDialog, QErrorMessage, QInputDialog, QLineEdit, QMessageBox + +from cutecoin.core.person import Person + +from cutecoin.gen_resources.certification_uic import Ui_CertificationDialog + + +class CertificationDialog(QDialog, Ui_CertificationDialog): + + ''' + classdocs + ''' + + def __init__(self, certifier): + ''' + Constructor + ''' + super().__init__() + self.setupUi(self) + self.certifier = certifier + self.community = self.certifier.communities[0] + + for community in self.certifier.communities: + self.combo_community.addItem(community.currency) + + for contact in certifier.contacts: + self.combo_contact.addItem(contact.name) + + def accept(self): + if self.radio_contact.isChecked(): + index = self.combo_contact.currentIndex() + pubkey = self.certifier.contacts[index].pubkey + else: + pubkey = self.edit_pubkey.text() + + password = QInputDialog.getText(self, "Account password", + "Please enter your password", + QLineEdit.Password) + if password[1] is True: + password = password[0] + else: + return + + while not self.certifier.check_password(password): + password = QInputDialog.getText(self, "Account password", + "Wrong password.\nPlease enter your password", + QLineEdit.Password) + if password[1] is True: + password = password[0] + else: + return + + try: + self.certifier.certify(password, self.community, pubkey) + QMessageBox.information(self, "Certification", + "Success certifying {0} from {1}".format(pubkey, + self.community.currency)) + except ValueError as e: + QMessageBox.critical(self, "Certification", + "Something wrong happened : {0}".format(e), + QMessageBox.Ok) + + self.accepted.emit() + self.close() + + def change_current_community(self, index): + self.community = self.certifier.communities[index] + + def recipient_mode_changed(self, pubkey_toggled): + self.edit_pubkey.setEnabled(pubkey_toggled) + self.combo_contact.setEnabled(not pubkey_toggled) diff --git a/src/cutecoin/gui/views/__init__.py b/src/cutecoin/gui/views/__init__.py new file mode 100644 index 00000000..e69de29b -- GitLab