def __init__(self, root_address: Address, channel_password = ''): self.tangle_con = TangleConnector() self.root_address = root_address.__str__() self.channel_pwd = channel_password self.current_write_addr = root_address.__str__() self.current_read_addr = root_address.__str__() self.trusted_pubkeys = {}
class TestTangleConnector(TestCase): def setUp(self): self.tangle_con = TangleConnector() def test_get_node(self): res = self.tangle_con.get_node() self.assertEqual(res['appName'], 'IRI') def test_get_tips(self): res = self.tangle_con.get_tips() self.assertTrue(res['hashes']) def test_get_hashes_from_addr(self): addr = Address( 'CBGEYVNQIBTQFLR999YHPIDSKBBN9FFLDZPAXHWULQDRTFNDHFYEPNEKQOEF9OCKQTPXFRLOCRXMBCOFCODPNDPNPZ' ) tx_list = self.tangle_con.get_hashes_from_addr(addr) self.assertTrue(tx_list) def test_get_trytes_from_hashes(self): tx = TransactionHash( b'LFHPLTGTTNCYZRCHHCQCBMGUJKFMEHWUDRMHHRUVWNTERXHVEYKWSMZDRLKSYLBFUVTTOFKOFLJI99999' ) trytes_list = self.tangle_con.get_trytes_from_hashes([tx]) self.assertTrue(trytes_list) def test_get_all_trytes_from_address(self): addr = Address( 'CBGEYVNQIBTQFLR999YHPIDSKBBN9FFLDZPAXHWULQDRTFNDHFYEPNEKQOEF9OCKQTPXFRLOCRXMBCOFCODPNDPNPZ' ) hashes_and_trytes = self.tangle_con.get_all_trytes_from_address(addr) self.assertTrue(hashes_and_trytes) def test_send_msg_to_addr(self): addr = Address( 'CBGEYVNQIBTQFLR999YHPIDSKBBN9FFLDZPAXHWULQDRTFNDHFYEPNEKQOEF9OCKQTPXFRLOCRXMBCOFCODPNDPNPZ' ) res = self.tangle_con.send_msg_to_addr(addr, 'test_string', 'TESTTAG') self.assertNotIn('Error', res.keys()) def test_get_bundles_from_addr(self): addr = Address( 'CBGEYVNQIBTQFLR999YHPIDSKBBN9FFLDZPAXHWULQDRTFNDHFYEPNEKQOEF9OCKQTPXFRLOCRXMBCOFCODPNDPNPZ' ) res = self.tangle_con.get_bundles_from_addr(addr) self.assertTrue(res) def test_get_messages_from_bundles(self): addr = Address( 'CBGEYVNQIBTQFLR999YHPIDSKBBN9FFLDZPAXHWULQDRTFNDHFYEPNEKQOEF9OCKQTPXFRLOCRXMBCOFCODPNDPNPZ' ) res = self.tangle_con.get_bundles_from_addr(addr) output = self.tangle_con.get_messages_from_bundles(res) self.assertTrue(output)
class TestTangleConnector(TestCase): def setUp(self): self.tangle_con = TangleConnector() def test_get_node(self): res = self.tangle_con.get_node() self.assertEqual(res['appName'], 'IRI') def test_get_tips(self): res = self.tangle_con.get_tips() self.assertTrue(res['hashes']) def test_get_hashes_from_addr(self): addr = Address( 'DU9DDSX9JOSPNFDTBCHYMLXTSB9YWIJTZZ9OMQSKUEMCGSCOVTXIQAH9WRCMGNVFCSUHPZWYLJZVCMGLAPHMVOBPAX' ) tx_list = self.tangle_con.get_hashes_from_addr(addr) self.assertTrue(tx_list) def test_get_trytes_from_hashes(self): tx = TransactionHash( b'LFHPLTGTTNCYZRCHHCQCBMGUJKFMEHWUDRMHHRUVWNTERXHVEYKWSMZDRLKSYLBFUVTTOFKOFLJI99999' ) trytes_list = self.tangle_con.get_trytes_from_hashes([tx]) self.assertTrue(trytes_list) def test_get_all_trytes_from_address(self): addr = Address( 'DU9DDSX9JOSPNFDTBCHYMLXTSB9YWIJTZZ9OMQSKUEMCGSCOVTXIQAH9WRCMGNVFCSUHPZWYLJZVCMGLAPHMVOBPAX' ) hashes_and_trytes = self.tangle_con.get_all_trytes_from_address(addr) self.assertTrue(hashes_and_trytes) def test_send_msg_to_addr(self): addr = Address( 'DU9DDSX9JOSPNFDTBCHYMLXTSB9YWIJTZZ9OMQSKUEMCGSCOVTXIQAH9WRCMGNVFCSUHPZWYLJZVCMGLAPHMVOBPAX' ) res = self.tangle_con.send_msg_to_addr(addr, 'test_string', 'TESTTAG') self.assertNotIn('Error', res.keys())
class MAML_Ed25519: def __init__(self, root_address: Address, channel_password = ''): self.tangle_con = TangleConnector() self.root_address = root_address.__str__() self.channel_pwd = channel_password self.current_write_addr = root_address.__str__() self.current_read_addr = root_address.__str__() self.trusted_pubkeys = {} @staticmethod def tryte_hash(msg: str): digest = SHA256.new() digest.update(msg.encode()) hash = digest.hexdigest() tryte_hash = TryteString.from_unicode(hash)[0:81] return tryte_hash.__str__() def _find_empty_addr(self): check_addr = self.current_read_addr while True: previous_addr = check_addr check_addr = self.tryte_hash(check_addr + self.channel_pwd) response = self._get_MAM_from_address(Address(check_addr)) if not response: self.current_write_addr = previous_addr break def _get_MAM_from_address(self, address: Address): # TODO need refactoring and to be able to handle bundles and validate JSONs for MAML protocol hashes_and_trytes = self.tangle_con.get_all_trytes_from_address(address) if hashes_and_trytes: trytes = hashes_and_trytes[list(hashes_and_trytes.keys())[0]] tx_json = self.tangle_con.get_json_from_tryte(trytes) else: return None try: if not self.trusted_pubkeys: is_trusted = True elif tx_json['pubkey'] in self.trusted_pubkeys: is_trusted = Ed25519Cipher.verify_signature((tx_json['data_payload'] + address.__str__()).encode(), tx_json['signature'].encode(), Ed25519Cipher.key_from_string(tx_json['pubkey'])) else: is_trusted = False if self.channel_pwd: tx_json['data_payload'] = AESCipher(self.channel_pwd).decrypt(tx_json['data_payload']) msg = Message(tx_json['data_payload'], tx_json['pubkey'], tx_json['signature'],tx_json['timestamp']) response = Response(address.__str__(), self.tryte_hash(address.__str__() + self.channel_pwd), msg, True, is_trusted) except: # empty response response = Response(address.__str__(), self.tryte_hash(address.__str__()+ self.channel_pwd), Message(), False, False) return response def write(self, data: str, pubkey, prikey): self._find_empty_addr() self.current_write_addr = self.tryte_hash(self.current_write_addr + self.channel_pwd) if self.channel_pwd: data = AESCipher(self.channel_pwd).encrypt(data).decode() msg = Message().finalize(data, self.current_write_addr, pubkey, prikey, int(time.time()) ) response_tangle = self.tangle_con.send_msg_to_addr(Address(self.current_write_addr), msg.__str__(), tag='PYTHONMAML') if response_tangle: response = Response(self.current_write_addr, self.tryte_hash(self.current_write_addr + self.channel_pwd), msg, True, True) else: response = None return response def read(self): previous_addr = self.current_read_addr self.current_read_addr = self.tryte_hash(self.current_read_addr + self.channel_pwd) response = self._get_MAM_from_address(Address(self.current_read_addr)) if response: return response else: self.current_read_addr = previous_addr return None def split_channel(self, new_channel_pwd): self._find_empty_addr() self.channel_pwd = new_channel_pwd self.current_read_addr = self.current_write_addr def add_trusted_pubkey(self, name: str, pubkey): pubkey_str = pubkey.to_ascii(encoding = 'base64').decode() if pubkey_str: self.trusted_pubkeys[pubkey_str] = name def del_trusted_pubkey(self, pubkey_str: str): if pubkey_str: self.trusted_pubkeys.pop(pubkey_str)
def __init__(self): self.tangle_con = TangleConnector()
class AuthCommunicator: def __init__(self): self.tangle_con = TangleConnector() def extract_valid_auth_txs(self, raw_messages: Dict) -> List[AuthTransaction]: ''' Extract valid AuthTransactions from list of raw messages :param raw_messages: Dict :return: List[AuthTransaction] ''' output_auth_tx = [] for tx_hash, raw_msg in raw_messages.items(): auth_msg = FactoryAuthMsg.create_auth_msg_from_json(raw_msg['msg']) is_valid = auth_msg.validate() if is_valid: auth_tx = AuthTransaction(tx_hash, raw_msg['address'], raw_msg['timestamp'], raw_msg['value'], auth_msg) output_auth_tx.append(auth_tx) return output_auth_tx def filter_valid_auth_txs(self, auth_txs: List[AuthTransaction], pubkeys_list: List[str] = None) \ -> List[AuthTransaction]: ''' Filter list of AuthTransactions against pubkeys_list. If pubkeys_list is not provided, all AuthTransactions pass the filter :param auth_txs: List[AuthTransaction] :param pubkeys_list: List[str] :return: List[AuthTransaction] ''' filtered_auth_txs = [] for tx in auth_txs: is_in_pubkey_list = (pubkeys_list and tx.auth_msg.pubkey in (pubkeys_list or [])) if (not pubkeys_list) or is_in_pubkey_list: filtered_auth_txs.append(tx) return filtered_auth_txs def get_auth_txs_from_address( self, address: Address, pubkeys_list: List[str] = None) -> List[AuthTransaction]: ''' Retrieve list of AuthTransaction from address, optionaly filter for some specific pubkeys :param address: Address :param pubkeys_list: List[str] :return: List[AuthTransaction] ''' raw_messages = self.tangle_con.get_all_msg_from_addr_by_bundle(address) auth_txs = self.extract_valid_auth_txs(raw_messages) return self.filter_valid_auth_txs(auth_txs, pubkeys_list) def send_msg(self, auth_msg: AuthMessage, address: Address, tag: str = 'AUTH9MSG') -> AuthTransaction: ''' Send AuthMessage to address :param auth_msg: AuthMessage :param address: Address :param tag: str :return: AuthTransaction ''' auth_tx = None if auth_msg.validate(): res = self.tangle_con.send_msg_to_addr(address, auth_msg.to_json(), tag) if res: bundle = res['bundle'].as_json_compatible()[0] auth_tx = AuthTransaction( bundle['bundle_hash'].__str__(), address.__str__(), bundle['timestamp'], 0, # value auth_msg) return auth_tx def send_msg_to_endpoint(self, auth_msg: AuthMessage, pubkey: str, tag: str = 'AUTH9MSG') -> AuthTransaction: ''' Send AuthMessage to the endpoint authenticated by the pubkey :param auth_msg: AuthMessage :param pubkey: str :param tag: str :return: AuthTransaction ''' endpoint_address = Address(hash_tryte(pubkey)) auth_tx = self.send_msg(auth_msg, endpoint_address, tag) return auth_tx def get_self_auth_txs_from_endpoint(self, pubkey: str) -> List[AuthTransaction]: ''' Retrieve list of AuthTransaction from endpoint authenticated by the pubkey and authored by the same pubkey :param address: Address :param pubkeys_list: List[str] :return: List[AuthTransaction] ''' endpoint_address = Address(hash_tryte(pubkey)) auth_tx = self.get_auth_txs_from_address(endpoint_address, [pubkey]) return auth_tx
from flask import Flask, jsonify from flask import render_template_string from iota import Address from ciphers import Ed25519Cipher from mam_lite import hash_tryte, AuthMessage, AuthCommunicator from tangle_connector import TangleConnector tangle_con = TangleConnector() auth_comm = AuthCommunicator() app = Flask(__name__) @app.route('/web+iota:/<pubkey>') def get_certficate(pubkey): auth_txs = auth_comm.get_self_auth_txs_from_endpoint(pubkey) if auth_txs: latest_auth_tx = sorted(auth_txs, key=lambda x: x.timestamp, reverse=True)[0] payload = latest_auth_tx.auth_msg.payload else: payload = f"No transactions from endpoint: {pubkey}" return render_template_string(payload) @app.route('/submit_page') def submit_page(): prikey, pubkey = Ed25519Cipher.generate_keys() pubkey_str = pubkey.to_ascii(encoding='base64').decode() address = hash_tryte(pubkey_str) html = ''' <!DOCTYPE html> <html>
def setUp(self): self.tangle_con = TangleConnector()