diff --git a/lib/ucoinpy/api/bma/wot/__init__.py b/lib/ucoinpy/api/bma/wot/__init__.py index 0de3bfc8a7d6d432a1d61ab7dc1ede2591bf19a6..ea9b9a236959a0def6cc9e28daac73a1df6f1446 100644 --- a/lib/ucoinpy/api/bma/wot/__init__.py +++ b/lib/ucoinpy/api/bma/wot/__init__.py @@ -37,6 +37,16 @@ class Add(WOT): return self.requests_post('/add', **kwargs).json() +class Revoke(WOT): + """POST Public key data.""" + + def __post__(self, **kwargs): + assert 'pubkey' in kwargs + assert 'self_' in kwargs + + return self.requests_post('/revoke', **kwargs).json() + + class Lookup(WOT): """GET Public key data.""" diff --git a/lib/ucoinpy/documents/certification.py b/lib/ucoinpy/documents/certification.py index ce5eff0e6a9007b247231c8841e6b2ee8de9a81b..3792839e593b9f46c2078b91fe867bad586192ac 100644 --- a/lib/ucoinpy/documents/certification.py +++ b/lib/ucoinpy/documents/certification.py @@ -105,3 +105,28 @@ class Certification(Document): return "{0}:{1}:{2}:{3}".format(self.pubkey_from, self.pubkey_to, self.blocknumber, self.signatures[0]) + +class Revocation(Document): + ''' + A document describing a self-revocation. + ''' + def __init__(self, version, currency, signature): + ''' + Constructor + ''' + super().__init__(version, currency, [signature]) + + def raw(self, selfcert): + return """{0}META:REVOKE +""".format(selfcert.signed_raw()) + + 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'))) + self.signatures.append(signing.decode("ascii")) + diff --git a/res/i18n/ts/fr_FR.ts b/res/i18n/ts/fr_FR.ts index 7f14e2027260b1eca5e9d0dd078a1f69edb04e72..290b64887a676bef337b1b0b559911e46e60cf65 100644 --- a/res/i18n/ts/fr_FR.ts +++ b/res/i18n/ts/fr_FR.ts @@ -271,62 +271,62 @@ <translation>Qualification : </translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="310"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="333"/> <source>Renew membership</source> <translation>Renouveller le statut de membre</translation> </message> <message> - <location filename="../../ui/community_tab.ui" line="139"/> + <location filename="../../ui/community_tab.ui" line="146"/> <source>Send leaving demand</source> <translation>Quitter la communauté</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="204"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="202"/> <source>Membership</source> <translation>Statut de membre</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="173"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="172"/> <source>Success sending membership demand</source> <translation>Succès lors de l'envoi d'une demande de membre</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="175"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="174"/> <source>Join demand error</source> <translation>Erreur lors de l'envoi d'une demande de membre</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="178"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="177"/> <source>Key not sent to community</source> <translation>La clé n'a pas pu être envoyée à la communauté</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="236"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="259"/> <source>Network error</source> <translation>Erreur réseau</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="236"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="259"/> <source>Couldn't connect to network : {0}</source> <translation>Impossible de se connecter au réseau : {0}</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="218"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="242"/> <source>Warning</source> <translation>Attention</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="204"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="202"/> <source>Success sending leaving demand</source> <translation>Succès lors de l'envoi de la demande pour quitter la communauté</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="233"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="204"/> <source>Leaving demand error</source> <translation>Erreur lors de l'envoi de la demande pour quitter la communauté</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="240"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="263"/> <source>Error</source> <translation>Erreur</translation> </message> @@ -341,12 +341,12 @@ <translation>Publier votre UID</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="59"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="58"/> <source>Members</source> <translation>Membres</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="62"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="61"/> <source>Direct connections</source> <translation>Connections directes</translation> </message> @@ -354,28 +354,28 @@ <location filename="../../../src/cutecoin/gui/community_tab.py" line="218"/> <source>Are you sure ? Publishing your UID cannot be canceled.</source> - <translation>Êtes vous certain ? + <translation type="obsolete">Êtes vous certain ? Publier votre UID ne peut être annulé.</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="230"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="227"/> <source>UID Publishing</source> <translation>Publication de l'UID</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="230"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="227"/> <source>Success publishing your UID</source> <translation>Succès lors de la publication de votre UID</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="178"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="177"/> <source>"Your key wasn't sent in the community. You can't request a membership.</source> <translation>Votre clé publique n'a pas été envoyée à la communauté. Vous ne pouvez pas envoyer de requête de membre.</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="191"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="190"/> <source>Are you sure ? Sending a leaving demand cannot be canceled. The process to join back the community later will have to be done again.</source> @@ -384,40 +384,77 @@ Envoyer une demande pour quitter la communauté ne peut être annulée. Le processus pour rejoindre la communauté devrait être refait à zéro.</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="58"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="57"/> <source>Web of Trust</source> <translation>Toile de Confiance</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="80"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="79"/> <source>Informations</source> <translation>Informations</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="84"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="83"/> <source>Add as contact</source> <translation>Ajouter comme contact</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="88"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="87"/> <source>Send money</source> <translation>Envoyer de l'argent</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="92"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="91"/> <source>Certify identity</source> <translation>Certifier cette identité</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="96"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="95"/> <source>View in Web of Trust</source> <translation>Voir dans la Toile de Confiance</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="316"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="340"/> <source>Send membership demand</source> <translation>Envoyer une demande de membre</translation> </message> + <message> + <location filename="../../ui/community_tab.ui" line="132"/> + <source>Revoke UID</source> + <translation>Révoquer votre UID</translation> + </message> + <message> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="216"/> + <source>Are you sure ? +Publishing your UID can be canceled by Revoke UID.</source> + <translation>Etes-vous sûr(e) ? Publier votre UID peut être annulé par le bouton Révoquer votre UID.</translation> + </message> + <message> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="230"/> + <source>Publish UID error</source> + <translation>Publier votre UID</translation> + </message> + <message> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="242"/> + <source>Are you sure ? +Revoking your UID can only success if it is not already validated by the network.</source> + <translation>Etes-vous sûr(e) ? Révoquer votre UID ne peut réussir que s'il n'a pas été déjà validé par le réseau.</translation> + </message> + <message> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="253"/> + <source>UID Revoking</source> + <translation>Révocation de votre UID</translation> + </message> + <message> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="253"/> + <source>Success revoking your UID</source> + <translation>Révocation de votre UID réussie</translation> + </message> + <message> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="256"/> + <source>Revoke UID error</source> + <translation>Erreur lors de la révocation de votre UID</translation> + </message> </context> <context> <name>ConfigureContactDialog</name> @@ -1037,22 +1074,22 @@ Le processus pour rejoindre la communauté devrait être refait à zéro.</trans <translation>Sauvegarder</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/mainwindow.py" line="359"/> + <location filename="../../../src/cutecoin/gui/mainwindow.py" line="364"/> <source>Export</source> <translation>Exporter</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/mainwindow.py" line="172"/> + <location filename="../../../src/cutecoin/gui/mainwindow.py" line="173"/> <source>Loading account {0}</source> <translation>Chargement du compte {0}</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/mainwindow.py" line="235"/> + <location filename="../../../src/cutecoin/gui/mainwindow.py" line="236"/> <source>Latest release : {version}</source> <translation>Dernière version : {version}</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/mainwindow.py" line="239"/> + <location filename="../../../src/cutecoin/gui/mainwindow.py" line="240"/> <source> <p><b>{version_info}</b></p> <p><a href={version_url}>Download link</a></p> @@ -1063,7 +1100,7 @@ Le processus pour rejoindre la communauté devrait être refait à zéro.</trans </translation> </message> <message> - <location filename="../../../src/cutecoin/gui/mainwindow.py" line="244"/> + <location filename="../../../src/cutecoin/gui/mainwindow.py" line="245"/> <source> <h1>Cutecoin</h1> @@ -1098,32 +1135,32 @@ Le processus pour rejoindre la communauté devrait être refait à zéro.</trans </translation> </message> <message> - <location filename="../../../src/cutecoin/gui/mainwindow.py" line="298"/> + <location filename="../../../src/cutecoin/gui/mainwindow.py" line="299"/> <source>Edit</source> <translation>Editer</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/mainwindow.py" line="301"/> + <location filename="../../../src/cutecoin/gui/mainwindow.py" line="302"/> <source>Delete</source> <translation>Supprimer</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/mainwindow.py" line="317"/> + <location filename="../../../src/cutecoin/gui/mainwindow.py" line="318"/> <source>CuteCoin {0}</source> <translation>CuteCoin {0}</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/mainwindow.py" line="341"/> + <location filename="../../../src/cutecoin/gui/mainwindow.py" line="342"/> <source>CuteCoin {0} - Account : {1}</source> <translation>CuteCoin {0} - Compte : {1}</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/mainwindow.py" line="357"/> + <location filename="../../../src/cutecoin/gui/mainwindow.py" line="362"/> <source>Export an account</source> <translation>Exporter un compte</translation> </message> <message> - <location filename="../../../src/cutecoin/gui/mainwindow.py" line="358"/> + <location filename="../../../src/cutecoin/gui/mainwindow.py" line="363"/> <source>All account files (*.acc)</source> <translation>Tout fichier de compte (*.acc)</translation> </message> diff --git a/res/ui/community_tab.ui b/res/ui/community_tab.ui index 82fa382fbb1a3b2675bb43388002ed364df17d24..aa2718ddddbe9bd7397085fa81a1360dbe1d3be1 100644 --- a/res/ui/community_tab.ui +++ b/res/ui/community_tab.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>457</width> - <height>369</height> + <width>636</width> + <height>404</height> </rect> </property> <property name="contextMenuPolicy"> @@ -126,6 +126,13 @@ </property> </widget> </item> + <item> + <widget class="QPushButton" name="button_revoke_uid"> + <property name="text"> + <string>Revoke UID</string> + </property> + </widget> + </item> <item> <widget class="QPushButton" name="button_membership"> <property name="text"> @@ -234,6 +241,22 @@ </hint> </hints> </connection> + <connection> + <sender>button_revoke_uid</sender> + <signal>clicked()</signal> + <receiver>CommunityTabWidget</receiver> + <slot>revoke_uid()</slot> + <hints> + <hint type="sourcelabel"> + <x>750</x> + <y>368</y> + </hint> + <hint type="destinationlabel"> + <x>622</x> + <y>201</y> + </hint> + </hints> + </connection> </connections> <slots> <slot>identity_context_menu(QPoint)</slot> @@ -241,5 +264,6 @@ <slot>send_membership_leaving()</slot> <slot>search_text()</slot> <slot>publish_uid()</slot> + <slot>revoke_uid()</slot> </slots> </ui> diff --git a/src/cutecoin/core/account.py b/src/cutecoin/core/account.py index 0aa477aaec2562e0802870a719116abbd2de9ba8..6c364f79b9d2b1807d989cdac86d6890f76c5dd4 100644 --- a/src/cutecoin/core/account.py +++ b/src/cutecoin/core/account.py @@ -6,7 +6,7 @@ Created on 1 févr. 2014 from ucoinpy import PROTOCOL_VERSION from ucoinpy.api import bma -from ucoinpy.documents.certification import SelfCertification, Certification +from ucoinpy.documents.certification import SelfCertification, Certification, Revocation from ucoinpy.documents.membership import Membership from ucoinpy.key import SigningKey @@ -231,13 +231,13 @@ class Account(QObject): self.wallets = self.wallets[:size] def certify(self, password, community, pubkey): - ''' + """ Certify an other identity :param str password: The account SigningKey password - :param community: The community target of the certification + :param cutecoin.core.community.Community community: The community target of the certification :param str pubkey: The certified identity pubkey - ''' + """ certified = Person.lookup(pubkey, community) blockid = community.current_blockid() @@ -259,6 +259,33 @@ class Account(QObject): logging.debug("Posted data : {0}".format(data)) community.broadcast(bma.wot.Add, {}, data) + def revoke(self, password, community): + """ + Revoke self-identity on server, not in blockchain + + :param str password: The account SigningKey password + :param cutecoin.core.community.Community community: The community target of the revocation + """ + revoked = Person.lookup(self.pubkey, community) + + revocation = Revocation(PROTOCOL_VERSION, community.currency, None) + + selfcert = revoked.selfcert(community) + + key = SigningKey(self.salt, password) + revocation.sign(selfcert, [key]) + + logging.debug("Self-Revocation Document : \n{0}".format(revocation.raw(selfcert))) + logging.debug("Signature : \n{0}".format(revocation.signatures[0])) + + data = { + 'pubkey': revoked.pubkey, + 'self_': selfcert.signed_raw(), + 'sig': revocation.signatures[0] + } + logging.debug("Posted data : {0}".format(data)) + community.broadcast(bma.wot.Revoke, {}, data) + def transfers(self, community): ''' Get all transfers done in a community by all the wallets diff --git a/src/cutecoin/core/net/node.py b/src/cutecoin/core/net/node.py index ec0bd8bb5c0d16b716753769ca3bc8beb0a578bc..c71bcce138130ea7b916c1a8ffa7a5d958db5f60 100644 --- a/src/cutecoin/core/net/node.py +++ b/src/cutecoin/core/net/node.py @@ -261,7 +261,7 @@ class Node(QObject): block = bma.blockchain.Current(self.endpoint.conn_handler()).get() block_number = block["number"] except ValueError as e: - if '404' in e: + if '404' in str(e): block_number = 0 peers_data = bma.network.peering.Peers(self.endpoint.conn_handler()).get() diff --git a/src/cutecoin/gui/community_tab.py b/src/cutecoin/gui/community_tab.py index df57be28753f8890fdd5629ee70ca3fb05ea38a2..0551280b7f6295d27dbb6d94d1e1fd4217c349c1 100644 --- a/src/cutecoin/gui/community_tab.py +++ b/src/cutecoin/gui/community_tab.py @@ -15,7 +15,6 @@ from cutecoin.gui.contact import ConfigureContactDialog from cutecoin.gui.member import MemberDialog from .wot_tab import WotTabWidget from .transfer import TransferMoneyDialog -from .password_asker import PasswordAskerDialog from .certification import CertificationDialog from . import toast from ..tools.exceptions import PersonNotFoundError, NoPeerAvailable @@ -194,9 +193,8 @@ Sending a leaving demand cannot be canceled. The process to join back the community later will have to be done again.""") .format(self.account.pubkey), QMessageBox.Ok | QMessageBox.Cancel) if reply == QMessageBox.Ok: - password_asker = PasswordAskerDialog(self.app.current_account) - password = password_asker.exec_() - if password_asker.result() == QDialog.Rejected: + password = self.password_asker.exec_() + if self.password_asker.result() == QDialog.Rejected: return try: @@ -204,7 +202,7 @@ The process to join back the community later will have to be done again.""") toast.display(self.tr("Membership"), self.tr("Success sending leaving demand")) except ValueError as e: QMessageBox.critical(self, self.tr("Leaving demand error"), - e.message) + str(e)) except NoPeerAvailable as e: QMessageBox.critical(self, self.tr("Network error"), self.tr("Couldn't connect to network : {0}").format(e), @@ -217,12 +215,11 @@ The process to join back the community later will have to be done again.""") def publish_uid(self): reply = QMessageBox.warning(self, self.tr("Warning"), self.tr("""Are you sure ? -Publishing your UID cannot be canceled.""") +Publishing your UID can be canceled by Revoke UID.""") .format(self.account.pubkey), QMessageBox.Ok | QMessageBox.Cancel) if reply == QMessageBox.Ok: - password_asker = PasswordAskerDialog(self.account) - password = password_asker.exec_() - if password_asker.result() == QDialog.Rejected: + password = self.password_asker.exec_() + if self.password_asker.result() == QDialog.Rejected: return try: @@ -230,8 +227,34 @@ Publishing your UID cannot be canceled.""") toast.display(self.tr("UID Publishing"), self.tr("Success publishing your UID")) except ValueError as e: - QMessageBox.critical(self, self.tr("Leaving demand error"), - e.message) + QMessageBox.critical(self, self.tr("Publish UID error"), + str(e)) + except NoPeerAvailable as e: + QMessageBox.critical(self, self.tr("Network error"), + self.tr("Couldn't connect to network : {0}").format(e), + QMessageBox.Ok) + except Exception as e: + QMessageBox.critical(self, self.tr("Error"), + "{0}".format(e), + QMessageBox.Ok) + + def revoke_uid(self): + reply = QMessageBox.warning(self, self.tr("Warning"), + self.tr("""Are you sure ? +Revoking your UID can only success if it is not already validated by the network.""") +.format(self.account.pubkey), QMessageBox.Ok | QMessageBox.Cancel) + if reply == QMessageBox.Ok: + password = self.password_asker.exec_() + if self.password_asker.result() == QDialog.Rejected: + return + + try: + self.account.revoke(password, self.community) + toast.display(self.tr("UID Revoking"), + self.tr("Success revoking your UID")) + except ValueError as e: + QMessageBox.critical(self, self.tr("Revoke UID error"), + str(e)) except NoPeerAvailable as e: QMessageBox.critical(self, self.tr("Network error"), self.tr("Couldn't connect to network : {0}").format(e), @@ -311,10 +334,12 @@ Publishing your UID cannot be canceled.""") self.button_membership.show() self.button_publish_uid.hide() self.button_leaving.show() + self.button_revoke_uid.hide() else: logging.debug("Not a member") self.button_membership.setText(self.tr("Send membership demand")) self.button_membership.show() + self.button_revoke_uid.show() self.button_leaving.hide() self.button_publish_uid.hide() else: @@ -322,6 +347,7 @@ Publishing your UID cannot be canceled.""") self.button_membership.hide() self.button_leaving.hide() self.button_publish_uid.show() + self.button_revoke_uid.hide() except PersonNotFoundError: self.button_membership.hide() self.button_leaving.hide()