diff --git a/lib/ucoinpy/api/bma/__init__.py b/lib/ucoinpy/api/bma/__init__.py index 57e861a78b00ceda64a6256fb8e3a84b30523ea4..02fac8a93ad16e4197878b6ffb0e6fa34ae04525 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 54b24ddc14a370333240acf536a57b49cf777af3..198b62b474c770b7440a0ac72c8d2d8d14eb61f7 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 1bf08afe0ea26b8aa259a8a00fe892b98e4c9032..031c69f1d3e7da54dde37631930a32bcda4a97cc 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 03898313e245b565e9ba1699bc690d8404889e77..582e2625e03c2fd38c137df53aa6204134e2900d 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 3f142a7f00147424641f6ca65a91b73ae2dc38f9..af71a3a0e07c381decd50e6207a5513ac63f935a 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 128da67ba160b656412dd679234701b391a87e22..6b437a6d3f72f05fcf65292075fac474dc273402 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 5b25bfae0e826d84d678a3676281e2b9f2185b09..2ba47ea89c585d9af302c7272a68943f103b0460 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 ce7d84a07403839a054fea235f1979a7cb37d6f8..24989c069c9a50fee2af52e82650882727e83c27 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 0000000000000000000000000000000000000000..fda8aba450a1ca89b154570dfdceb5113173aeb4 --- /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 45c675aceee234687c9b2f7db4a65d02da59e132..426ce09f7093ec6fc5cc33d5771fad7223022b13 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 f833d2e641e87a10198623a55cbbdff0c920f501..a1c032a04270ae40bea9df7a325046aee93bf42a 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 0000000000000000000000000000000000000000..d31c00ffe7e767493bf672494776b798791b751e --- /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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391