Commit 00ccf3b4 authored by Vincent Texier's avatar Vincent Texier

issue #52 Refactor Revocation document to respect superclass overload (break BC)

Revocation methods respect documents methods arguments
Revocation accept Identity or pubkey in constructor
Revocation created from inline needs to have self.identity populated later
to use raw/sign/signed_raw methods
parent 21914877
......@@ -328,9 +328,6 @@ CertTimestamp: {timestamp}
RevocationType = TypeVar('RevocationType', bound='Revocation')
# todo: Revocation document should be created with the revoked Identity document in arguments
class Revocation(Document):
"""
A document describing a self-revocation.
......@@ -354,23 +351,28 @@ class Revocation(Document):
"IdtySignature": re_idtysignature,
}}
def __init__(self, version: int, currency: str, pubkey: str, signature: str) -> None:
def __init__(self, version: int, currency: str, identity: Union[Identity, str], signature: str) -> None:
"""
Init Revocation instance
:param version: Version number
:param currency: Name of the currency
:param pubkey: Public key of the issuer
:param identity: Identity instance or identity pubkey
:param signature: Signature
"""
super().__init__(version, currency, [signature])
self.pubkey = pubkey
self.identity = identity if isinstance(identity, Identity) else None
self.pubkey = identity.pubkey if isinstance(identity, Identity) else identity
@classmethod
def from_inline(cls: Type[RevocationType], version: int, currency: str, inline: str) -> RevocationType:
"""
Return Revocation document instance from inline string
Only self.pubkey is populated.
You must populate self.identity with an Identity instance to use raw/sign/signed_raw methods
:param version: Version number
:param currency: Name of the currency
:param inline: Inline document
......@@ -405,12 +407,23 @@ class Revocation(Document):
n += 1
issuer = Revocation.parse_field("Issuer", lines[n])
n += 4
n += 1
identity_uid = Revocation.parse_field("IdtyUniqueID", lines[n])
n += 1
identity_timestamp = Revocation.parse_field("IdtyTimestamp", lines[n])
n += 1
identity_signature = Revocation.parse_field("IdtySignature", lines[n])
n += 1
signature = Revocation.parse_field("Signature", lines[n])
n += 1
return cls(version, currency, issuer, signature)
identity = Identity(version, currency, issuer, identity_uid, identity_timestamp, identity_signature)
return cls(version, currency, identity, signature)
@staticmethod
def extract_self_cert(signed_raw: str) -> Identity:
......@@ -454,13 +467,15 @@ class Revocation(Document):
"""
return "{0}:{1}".format(self.pubkey, self.signatures[0])
def raw_for_revoked(self, revoked: Identity) -> str:
def raw(self) -> str:
"""
Return Revocation raw document string from Identity instance
Return Revocation raw document string
:param Identity revoked: Identity instance
:return:
"""
if not isinstance(self.identity, Identity):
raise MalformedDocumentError("Can not return full revocation document created from inline")
return """Version: {version}
Type: Revocation
Currency: {currency}
......@@ -470,33 +485,37 @@ IdtyTimestamp: {timestamp}
IdtySignature: {signature}
""".format(version=self.version,
currency=self.currency,
pubkey=revoked.pubkey,
uid=revoked.uid,
timestamp=revoked.timestamp,
signature=revoked.signatures[0])
pubkey=self.identity.pubkey,
uid=self.identity.uid,
timestamp=self.identity.timestamp,
signature=self.identity.signatures[0])
def sign_for_revoked(self, revoked: Identity, keys: list) -> None:
def sign(self, keys: list) -> None:
"""
Sign the current document.
Warning : current signatures will be replaced with the new ones.
:param revoked: Identity instance
:param keys: List of libnacl key instances
:return:
"""
if not isinstance(self.identity, Identity):
raise MalformedDocumentError("Can not return full revocation document created from inline")
self.signatures = []
for key in keys:
signing = base64.b64encode(key.signature(bytes(self.raw_for_revoked(revoked), 'ascii')))
signing = base64.b64encode(key.signature(bytes(self.raw(), 'ascii')))
self.signatures.append(signing.decode("ascii"))
def signed_raw_for_revoked(self, revoked: Identity) -> str:
def signed_raw(self) -> str:
"""
Return Revocation signed raw document string for revoked Identity instance
Return Revocation signed raw document string
:param revoked: Identity instance
:return:
"""
raw = self.raw_for_revoked(revoked)
if not isinstance(self.identity, Identity):
raise MalformedDocumentError("Can not return full revocation document created from inline")
raw = self.raw()
signed = "\n".join(self.signatures)
signed_raw = raw + signed + "\n"
return signed_raw
......@@ -84,11 +84,11 @@ def get_signed_raw_revocation_document(identity: Identity, salt: str, password:
:rtype: str
"""
revocation = Revocation(PROTOCOL_VERSION, identity.currency, identity.pubkey, "")
revocation = Revocation(PROTOCOL_VERSION, identity.currency, identity, "")
key = SigningKey(salt, password)
revocation.sign_for_revoked(identity, [key])
return revocation.signed_raw_for_revoked(identity)
revocation.sign([key])
return revocation.signed_raw()
async def main():
......
......@@ -126,10 +126,10 @@ SoKwoa8PFfCDJWZ6dNCv7XstezHcc2BbKiJgVDXv82R5zYR83nis9dShLgWJ5w48noVUHimdngzYQneN
currency = "beta_brousouf"
pubkey = "HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd"
signature = "SoKwoa8PFfCDJWZ6dNCv7XstezHcc2BbKiJgVDXv82R5zYR83nis9dShLgWJ5w48noVUHimdngzYQneNYSMV3rk"
revokation = Revocation(version, currency, pubkey, signature)
selfcert = Identity(version, currency, pubkey, "lolcat",
identity = Identity(version, currency, pubkey, "lolcat",
BlockUID(32, "DB30D958EE5CB75186972286ED3F4686B8A1C2CD"),
"J3G9oM5AKYZNLAB5Wx499w61NuUoS57JVccTShUbGpCMjCqj9yXXqNq7dyZpDWA6BxipsiaMZhujMeBfCznzyci")
revokation = Revocation(version, currency, identity, signature)
result = """Version: 2
Type: Revocation
......@@ -140,7 +140,7 @@ IdtyTimestamp: 32-DB30D958EE5CB75186972286ED3F4686B8A1C2CD
IdtySignature: J3G9oM5AKYZNLAB5Wx499w61NuUoS57JVccTShUbGpCMjCqj9yXXqNq7dyZpDWA6BxipsiaMZhujMeBfCznzyci
SoKwoa8PFfCDJWZ6dNCv7XstezHcc2BbKiJgVDXv82R5zYR83nis9dShLgWJ5w48noVUHimdngzYQneNYSMV3rk
"""
self.assertEqual(revokation.signed_raw_for_revoked(selfcert), result)
self.assertEqual(revokation.signed_raw(), result)
def test_revokation_from_signed_raw(self):
signed_raw = """Version: 2
......@@ -153,5 +153,5 @@ IdtySignature: J3G9oM5AKYZNLAB5Wx499w61NuUoS57JVccTShUbGpCMjCqj9yXXqNq7dyZpDWA6B
SoKwoa8PFfCDJWZ6dNCv7XstezHcc2BbKiJgVDXv82R5zYR83nis9dShLgWJ5w48noVUHimdngzYQneNYSMV3rk
"""
revocation = Revocation.from_signed_raw(signed_raw)
selfcert = Revocation.extract_self_cert(signed_raw)
self.assertEqual(revocation.signed_raw_for_revoked(selfcert), signed_raw)
self.assertTrue(isinstance(Revocation.extract_self_cert(signed_raw), Identity))
self.assertEqual(revocation.signed_raw(), signed_raw)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment