From 36e4be7db168713b1b178e5af9c9427441763854 Mon Sep 17 00:00:00 2001 From: Vincent Texier <vit@free.fr> Date: Sun, 24 May 2015 18:12:37 +0200 Subject: [PATCH] Implement Revoke UID button [WORK IN PROGRESS - BROKEN] fixme : Revocation signature is wrong --- lib/ucoinpy/api/bma/wot/__init__.py | 10 ++++ lib/ucoinpy/documents/certification.py | 25 ++++++++ res/i18n/ts/fr_FR.ts | 81 +++++++++++++++++++------- res/ui/community_tab.ui | 28 ++++++++- src/cutecoin/core/account.py | 35 +++++++++-- src/cutecoin/gui/community_tab.py | 45 ++++++++++---- 6 files changed, 186 insertions(+), 38 deletions(-) diff --git a/lib/ucoinpy/api/bma/wot/__init__.py b/lib/ucoinpy/api/bma/wot/__init__.py index 0de3bfc8..ea9b9a23 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 ce5eff0e..517d5bcf 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]) + + @staticmethod + def raw(): + return """META:REVOKE""" + + 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(selfcert.signed_raw() + self.raw(), 'ascii'))) + self.signatures.append(signing.decode("ascii")) + diff --git a/res/i18n/ts/fr_FR.ts b/res/i18n/ts/fr_FR.ts index 7f14e202..70a87ab7 100644 --- a/res/i18n/ts/fr_FR.ts +++ b/res/i18n/ts/fr_FR.ts @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> -<!DOCTYPE TS><TS version="2.0" language="fr_FR" sourcelanguage="en"> +<!DOCTYPE TS> +<TS version="2.0" language="fr_FR" sourcelanguage="en"> <context> <name>@default</name> <message> @@ -271,12 +272,12 @@ <translation>Qualification : </translation> </message> <message> - <location filename="../../../src/cutecoin/gui/community_tab.py" line="310"/> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="337"/> <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> @@ -301,17 +302,17 @@ <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="263"/> <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="263"/> <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="245"/> <source>Warning</source> <translation>Attention</translation> </message> @@ -321,12 +322,12 @@ <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="206"/> <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="267"/> <source>Error</source> <translation>Erreur</translation> </message> @@ -354,7 +355,7 @@ <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> @@ -414,10 +415,48 @@ Le processus pour rejoindre la communauté devrait être refait à zéro.</trans <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="343"/> <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="218"/> + <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="233"/> + <source>Publish UID error</source> + <translatorcomment>Erreur lors de la publication de votre UID</translatorcomment> + <translation>Publier votre UID</translation> + </message> + <message> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="245"/> + <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="257"/> + <source>UID Revoking</source> + <translation>Révocation de votre UID</translation> + </message> + <message> + <location filename="../../../src/cutecoin/gui/community_tab.py" line="257"/> + <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="260"/> + <source>Revoke UID error</source> + <translation>Erreur lors de la révocation de votre UID</translation> + </message> </context> <context> <name>ConfigureContactDialog</name> @@ -1037,22 +1076,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 +1102,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 +1137,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 82fa382f..aa2718dd 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 0aa477aa..ba749ac6 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(selfcert.signed_raw() + revocation.raw())) + 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/gui/community_tab.py b/src/cutecoin/gui/community_tab.py index df57be28..1241d151 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), -- GitLab