diff --git a/duniterpy/documents/block.py b/duniterpy/documents/block.py index b7db3730ee0ba11a4a4eb737d08ecc4ca4bdff51..1cc81e31b33a341a807bc0d255fc1477b28b5656 100644 --- a/duniterpy/documents/block.py +++ b/duniterpy/documents/block.py @@ -176,6 +176,7 @@ class Block(Document): transactions: List[Transaction], inner_hash: str, nonce: int, + signing_key: SigningKey = None, ) -> None: """ Constructor @@ -206,6 +207,7 @@ class Block(Document): :param transactions: transactions documents :param inner_hash: the block hash :param nonce: the nonce value of the block + :param signing_key: SigningKey instance to sign the document (default=None) """ super().__init__(version, currency) @@ -247,6 +249,9 @@ class Block(Document): self.inner_hash = inner_hash self.nonce = nonce + if signing_key is not None: + self.sign(signing_key) + @property def blockUID(self) -> BlockUID: """ diff --git a/duniterpy/documents/certification.py b/duniterpy/documents/certification.py index 3f87f6d3d49e0e6f11daa4d6ba426727bf6a6f7d..10b926c2be4016c6cb4bed50aa7d9c318bab030c 100644 --- a/duniterpy/documents/certification.py +++ b/duniterpy/documents/certification.py @@ -60,6 +60,7 @@ class Certification(Document): pubkey_from: str, identity: Union[Identity, str], timestamp: BlockUID, + signing_key: SigningKey = None, ) -> None: """ Constructor @@ -69,6 +70,7 @@ class Certification(Document): :param pubkey_from: Pubkey of the certifier :param identity: Document instance of the certified identity or identity pubkey string :param timestamp: the blockuid + :param signing_key: SigningKey instance to sign the document (default=None) """ super().__init__(version, currency) self.pubkey_from = pubkey_from @@ -76,6 +78,9 @@ class Certification(Document): self.pubkey_to = identity.pubkey if isinstance(identity, Identity) else identity self.timestamp = timestamp + if signing_key is not None: + self.sign(signing_key) + @classmethod def from_signed_raw( cls: Type[CertificationType], signed_raw: str diff --git a/duniterpy/documents/identity.py b/duniterpy/documents/identity.py index de4c003af6b0ac2f238fb5683f75afc0781e58ca..ab8222ca1e3cc13f9a663412ae88107064ab3d7d 100644 --- a/duniterpy/documents/identity.py +++ b/duniterpy/documents/identity.py @@ -17,10 +17,12 @@ import re from typing import Type, TypeVar from ..constants import BLOCK_UID_REGEX, PUBKEY_REGEX, SIGNATURE_REGEX, UID_REGEX + +# required to type hint cls in classmethod +from ..key import SigningKey from .block_uid import BlockUID from .document import Document, MalformedDocumentError -# required to type hint cls in classmethod IdentityType = TypeVar("IdentityType", bound="Identity") @@ -77,7 +79,13 @@ class Identity(Document): } def __init__( - self, version: int, currency: str, pubkey: str, uid: str, timestamp: BlockUID + self, + version: int, + currency: str, + pubkey: str, + uid: str, + timestamp: BlockUID, + signing_key: SigningKey = None, ) -> None: """ Create an identity document @@ -87,6 +95,7 @@ class Identity(Document): :param pubkey: Public key of the account linked to the identity :param uid: Unique identifier :param timestamp: BlockUID instance + :param signing_key: SigningKey instance to sign the document (default=None) """ super().__init__(version, currency) @@ -94,6 +103,9 @@ class Identity(Document): self.timestamp = timestamp self.uid = uid + if signing_key is not None: + self.sign(signing_key) + @classmethod def from_inline( cls: Type[IdentityType], version: int, currency: str, inline: str diff --git a/duniterpy/documents/membership.py b/duniterpy/documents/membership.py index fe4ebe826d66f333dbab6613837a2f23fd1d4fa9..0bfb90710302072f594fc2343255af2126bf8f1b 100644 --- a/duniterpy/documents/membership.py +++ b/duniterpy/documents/membership.py @@ -17,10 +17,12 @@ import re from typing import Type, TypeVar from ..constants import BLOCK_UID_REGEX, PUBKEY_REGEX, SIGNATURE_REGEX + +# required to type hint cls in classmethod +from ..key import SigningKey from .block_uid import BlockUID from .document import Document, MalformedDocumentError -# required to type hint cls in classmethod MembershipType = TypeVar("MembershipType", bound="Membership") @@ -82,6 +84,7 @@ class Membership(Document): membership_type: str, uid: str, identity_ts: BlockUID, + signing_key: SigningKey = None, ) -> None: """ Create a membership document @@ -93,6 +96,7 @@ class Membership(Document): :param membership_type: "IN" or "OUT" to enter or quit the community :param uid: Unique identifier of the identity :param identity_ts: BlockUID of the identity + :param signing_key: SigningKey instance to sign the document (default=None) """ super().__init__(version, currency) @@ -102,6 +106,9 @@ class Membership(Document): self.uid = uid self.identity_ts = identity_ts + if signing_key is not None: + self.sign(signing_key) + @classmethod def from_inline( cls: Type[MembershipType], diff --git a/duniterpy/documents/peer.py b/duniterpy/documents/peer.py index 3189b1543076b7a40565af45c8238b64bc856c72..a7c0ce6268cd7246d91fb3ff5379694a45722990 100644 --- a/duniterpy/documents/peer.py +++ b/duniterpy/documents/peer.py @@ -19,10 +19,12 @@ from typing import List, Type, TypeVar from duniterpy.api.endpoint import Endpoint, endpoint from ..constants import BLOCK_HASH_REGEX, PUBKEY_REGEX + +# required to type hint cls in classmethod +from ..key import SigningKey from .block_uid import BlockUID from .document import Document, MalformedDocumentError -# required to type hint cls in classmethod PeerType = TypeVar("PeerType", bound="Peer") @@ -69,6 +71,7 @@ class Peer(Document): pubkey: str, block_uid: BlockUID, endpoints: List[Endpoint], + signing_key: SigningKey = None, ) -> None: """ Init Peer instance @@ -78,6 +81,7 @@ class Peer(Document): :param pubkey: Public key of the issuer :param block_uid: BlockUID instance timestamp :param endpoints: List of endpoints string + :param signing_key: SigningKey instance to sign the document (default=None) """ super().__init__(version, currency) @@ -85,6 +89,9 @@ class Peer(Document): self.blockUID = block_uid self.endpoints: List[Endpoint] = endpoints + if signing_key is not None: + self.sign(signing_key) + @classmethod def from_signed_raw(cls: Type[PeerType], raw: str) -> PeerType: """ diff --git a/duniterpy/documents/revocation.py b/duniterpy/documents/revocation.py index 789a147e6ab1f0b79bfa6b06712f3ab40419085f..1e030941db953b89bc3787f871df055ddc57d461 100644 --- a/duniterpy/documents/revocation.py +++ b/duniterpy/documents/revocation.py @@ -61,7 +61,11 @@ class Revocation(Document): } def __init__( - self, version: int, currency: str, identity: Union[Identity, str] + self, + version: int, + currency: str, + identity: Union[Identity, str], + signing_key: SigningKey = None, ) -> None: """ Init Revocation instance @@ -69,12 +73,16 @@ class Revocation(Document): :param version: Version number :param currency: Name of the currency :param identity: Identity instance or identity pubkey + :param signing_key: SigningKey instance to sign the document (default=None) """ super().__init__(version, currency) self.identity = identity if isinstance(identity, Identity) else None self.pubkey = identity.pubkey if isinstance(identity, Identity) else identity + if signing_key is not None: + self.sign(signing_key) + @classmethod def from_inline( cls: Type[RevocationType], version: int, currency: str, inline: str diff --git a/duniterpy/documents/transaction.py b/duniterpy/documents/transaction.py index c384f774a6aeec5c5021c5e86fd0aa0b3e5afb93..2d2e32b8dee3424532bd0ff9e18a3a55589a50fe 100644 --- a/duniterpy/documents/transaction.py +++ b/duniterpy/documents/transaction.py @@ -548,6 +548,7 @@ class Transaction(Document): outputs: List[OutputSource], comment: str, time: Optional[int] = None, + signing_key: SigningKey = None, ) -> None: """ Init Transaction instance @@ -562,6 +563,7 @@ class Transaction(Document): :param outputs: List of OutputSource instances :param comment: Comment field :param time: time when the transaction enters the blockchain + :param signing_key: SigningKey instance to sign the document (default=None) """ super().__init__(version, currency) self.blockstamp = blockstamp @@ -574,6 +576,9 @@ class Transaction(Document): self.time = time self.signatures: List[str] = list() + if signing_key is not None: + self.sign(signing_key) + def __eq__(self, other: Any) -> bool: """ Check Transaction instances equality @@ -995,6 +1000,7 @@ class SimpleTransaction(Transaction): outputs: List[OutputSource], comment: str, time: int, + signing_key: SigningKey = None, ) -> None: """ Init instance @@ -1009,6 +1015,7 @@ class SimpleTransaction(Transaction): :param outputs: List of OutputSource instances :param comment: Comment field :param time: time when the transaction enters the blockchain + :param signing_key: SigningKey instance to sign the document (default=None) """ super().__init__( version, @@ -1021,6 +1028,7 @@ class SimpleTransaction(Transaction): outputs, comment, time, + signing_key=signing_key, ) @staticmethod diff --git a/examples/save_revoke_document.py b/examples/save_revoke_document.py index c67a478b3c9dbaf2d5b3b50e4deabf5f78fe19b7..33b274503b01b7eb791b056a9d5ffed4b158adcb 100644 --- a/examples/save_revoke_document.py +++ b/examples/save_revoke_document.py @@ -84,10 +84,9 @@ def get_signed_raw_revocation_document( :rtype: str """ - revocation = Revocation(PROTOCOL_VERSION, identity.currency, identity) - key = SigningKey.from_credentials(salt, password) - revocation.sign(key) + revocation = Revocation(PROTOCOL_VERSION, identity.currency, identity, key) + return revocation.signed_raw() @@ -122,7 +121,7 @@ def save_revoke_document(): # capture current block to get currency name current_block = client(bma.blockchain.current) - # create our Identity document to sign the Certification document + # create our Identity document to sign the revocation document identity = get_identity_document(client, current_block, pubkey) if identity is None: print("Identity not found for pubkey {0}".format(pubkey)) diff --git a/examples/send_certification.py b/examples/send_certification.py index 81d19ec1fdfb5b3476f6bb66eba36e392b900b9f..2d20578ee21f8415c977c67b7fd381efa92c8f3d 100644 --- a/examples/send_certification.py +++ b/examples/send_certification.py @@ -57,14 +57,14 @@ def get_identity_document( def get_certification_document( - current_block: dict, self_cert_document: Identity, from_pubkey: str + current_block: dict, identity: Identity, signing_key: SigningKey ) -> Certification: """ Create and return a Certification document :param current_block: Current block data - :param self_cert_document: Identity document - :param from_pubkey: Pubkey of the certifier + :param identity: Identity document instance + :param signing_key: Signing key of the certifier :rtype: Certification """ @@ -72,9 +72,10 @@ def get_certification_document( return Certification( version=10, currency=current_block["currency"], - pubkey_from=from_pubkey, - identity=self_cert_document, + pubkey_from=signing_key.pubkey, + identity=identity, timestamp=BlockUID(current_block["number"], current_block["hash"]), + signing_key=signing_key, ) @@ -97,7 +98,6 @@ def send_certification(): # create key from credentials key = SigningKey.from_credentials(salt, password) - pubkey_from = key.pubkey # prompt entry pubkey_to = input("Enter pubkey to certify: ") @@ -113,10 +113,7 @@ def send_certification(): return # send the Certification document to the node - certification = get_certification_document(current_block, identity, pubkey_from) - - # sign document - certification.sign([key]) + certification = get_certification_document(current_block, identity, key) # Here we request for the path wot/certify try: diff --git a/examples/send_identity.py b/examples/send_identity.py index cefcecc53f6d3b816bd3feec3a37b3d1fdec471a..4b58bfc849128977a3e5e35476047c23b1b2015b 100644 --- a/examples/send_identity.py +++ b/examples/send_identity.py @@ -57,11 +57,9 @@ def get_identity_document( pubkey=key.pubkey, uid=uid, timestamp=timestamp, + signing_key=key, ) - # sign document - identity.sign(key) - return identity diff --git a/examples/send_membership.py b/examples/send_membership.py index 3d49beb9b66462cd3153e7c8798a481ad4724e6a..e47526cdafe4b024e1f0021e500eb942ee39e49f 100644 --- a/examples/send_membership.py +++ b/examples/send_membership.py @@ -65,11 +65,9 @@ def get_membership_document( membership_type=membership_type, uid=uid, identity_ts=identity_timestamp, + signing_key=key, ) - # sign document - membership.sign(key) - return membership diff --git a/examples/send_transaction.py b/examples/send_transaction.py index 983c17a2a8b1b5c94da41a7b77903393feed5c5c..537ba3fa0520badfffba545d602593a953ce92ff 100644 --- a/examples/send_transaction.py +++ b/examples/send_transaction.py @@ -42,7 +42,11 @@ TRANSACTION_VERSION = 10 def get_transaction_document( - current_block: dict, source: dict, from_pubkey: str, to_pubkey: str + current_block: dict, + source: dict, + from_pubkey: str, + to_pubkey: str, + signing_key: SigningKey, ) -> Transaction: """ Return a Transaction document @@ -51,6 +55,7 @@ def get_transaction_document( :param source: Source to send :param from_pubkey: Public key of the issuer :param to_pubkey: Public key of the receiver + :param signing_key: Signing key of the issuer :return: Transaction """ @@ -97,6 +102,7 @@ def get_transaction_document( unlocks=unlocks, outputs=outputs, comment="", + signing_key=signing_key, ) return transaction @@ -141,12 +147,9 @@ def send_transaction(): # create the transaction document transaction = get_transaction_document( - current_block, source, pubkey_from, pubkey_to + current_block, source, pubkey_from, pubkey_to, key ) - # sign document - transaction.sign([key]) - # send the Transaction document to the node try: client(bma.tx.process, transaction.signed_raw())