def gogogox(todo, amount, account_no):
    print('gogogo')
    context = create_context('secp256k1')
    #    conn = sqlite3.connect('bank.db')
    #    cursor = conn.execute("SELECT private_key from key")
    #    for row in cursor:
    #        privatek=row[0]
    #    conn.close()
    #    private_key = Secp256k1PrivateKey.from_hex(privatek)
    conn = sqlite3.connect('bank.db')

    cursor = conn.execute(
        "SELECT code from BANK WHERE account_no='{}'".format(account_no))
    for row in cursor:
        code = row[0]
    conn.close()
    private_key = context.new_random_private_key()
    signer = CryptoFactory(context).new_signer(private_key)

    input = hash("bankregister".encode('utf-8'))[0:6] + hash(
        "overclockedbrain".encode('utf-8'))[0:58] + hash(
            code.encode('utf-8'))[0:6]
    payload = "{},{},{}".format(todo, amount, code)
    payload_bytes = cbor.dumps(payload)
    txn_header_bytes = TransactionHeader(
        family_name='bankregister',
        family_version='1.0',
        inputs=[input],
        outputs=[input],
        signer_public_key=signer.get_public_key().as_hex(),
        batcher_public_key=signer.get_public_key().as_hex(),
        dependencies=[],
        payload_sha512=sha512(payload_bytes).hexdigest()).SerializeToString()
    signature = signer.sign(txn_header_bytes)

    txn = Transaction(header=txn_header_bytes,
                      header_signature=signature,
                      payload=payload_bytes)
    txns = [txn]

    batch_header_bytes = BatchHeader(
        signer_public_key=signer.get_public_key().as_hex(),
        transaction_ids=[txn.header_signature for txn in txns],
    ).SerializeToString()

    signature = signer.sign(batch_header_bytes)

    batch = Batch(header=batch_header_bytes,
                  header_signature=signature,
                  transactions=txns)
    batch_list_bytes = BatchList(batches=[batch]).SerializeToString()
    return batch_list_bytes
async def create_account(request):
    """Creates a new Account and corresponding authorization token"""
    required_fields = ['email', 'password']
    common.validate_fields(required_fields, request.json)

    private_key = request.app.config.CONTEXT.new_random_private_key()
    signer = CryptoFactory(request.app.config.CONTEXT).new_signer(private_key)
    public_key = signer.get_public_key().as_hex()

    auth_entry = _create_auth_dict(request, public_key, private_key.as_hex())
    await auth_query.create_auth_entry(request.app.config.DB_CONN, auth_entry)

    account = _create_account_dict(request.json, public_key)

    batches, batch_id = transaction_creation.create_account(
        txn_key=signer,
        batch_key=request.app.config.SIGNER,
        label=account.get('label'),
        description=account.get('description'))

    await messaging.send(request.app.config.VAL_CONN,
                         request.app.config.TIMEOUT, batches)

    try:
        await messaging.check_batch_status(request.app.config.VAL_CONN,
                                           batch_id)
    except (ApiBadRequest, ApiInternalError) as err:
        await auth_query.remove_auth_entry(request.app.config.DB_CONN,
                                           request.json.get('email'))
        raise err

    token = common.generate_auth_token(request.app.config.SECRET_KEY,
                                       account.get('email'), public_key)

    return response.json({'authorization': token, 'account': account})
Beispiel #3
0
async def create_account(request):
    """Creates a new Account and corresponding authorization token"""
    # required_fields = ['email', 'password']
    # common.validate_fields(required_fields, request.json)

    privateKey = request.app.config.CONTEXT.new_random_private_key()
    signer = CryptoFactory(request.app.config.CONTEXT).new_signer(privateKey)
    public_key = signer.get_public_key().as_hex()
    private_key = signer.get_public_key().as_hex()

    # auth_entry = _create_auth_dict(
    #     request, public_key, private_key.as_hex())
    # await auth_query.create_auth_entry(request.app.config.DB_CONN, auth_entry)

    # account = _create_account_dict(request.json, public_key)

    # batches, batch_id = transaction_creation.create_account(
    #     txn_key=signer,
    #     batch_key=request.app.config.SIGNER,
    #     label=account.get('label'),
    #     description=account.get('description'))

    # await messaging.send(
    #     request.app.config.VAL_CONN,
    #     request.app.config.TIMEOUT,
    #     batches)

    # try:
    #     await messaging.check_batch_status(
    #         request.app.config.VAL_CONN, batch_id)
    # except (ApiBadRequest, ApiInternalError) as err:
    #     await auth_query.remove_auth_entry(
    #         request.app.config.DB_CONN, request.json.get('email'))
    #     raise err

    # token = common.generate_auth_token(
    #     request.app.config.SECRET_KEY,
    #     account.get('email'),
    #     public_key)

    print('private_key', private_key)
    print('public_key', public_key)
    return response.json({
        'private_key': private_key,
        'public_key': public_key
    })
Beispiel #4
0
 def apply(self, transaction, context):
     '''This implements the apply function for this transaction handler.
                                                           
        This function does most of the work for this class by processing
        a single transaction for the carLogger transaction family.
     '''
     LOGGER.debug("start" )
     # Get the payload and extract carLogger-specific information.
     header = transaction.header
     from_key = header.signer_public_key
     payload_list = transaction.payload.decode().split(",")
     operation = payload_list[0]
     VIN = payload_list[1]
     signer = CryptoFactory(create_context('secp256k1')) \
         .new_signer(Secp256k1PrivateKey.from_hex(payload_list[2]))
     work_date = payload_list[3]
     company = signer.get_public_key().as_hex()
     log = VehicleLog(VIN=VIN, worker=company, work_date=work_date)
     # Perform the operation.
     LOGGER.info("Operation = "+ operation)
     if operation == "add":
         work = payload_list[4]
         km_status = payload_list[5]
         description = payload_list[6]
         log.work = work
         log.mileage = km_status
         log.description = description
         log.timestamp = str(time.strftime("%Y-%m-%d %H:%M"))
         self._add(context, log)
     elif operation == "delete":
         work = payload_list[4]
         km_status = payload_list[5]
         description = payload_list[6]
         log.mileage = km_status
         log.description = description
         log.timestamp = str(time.strftime("%Y-%m-%d %H:%M"))
         deleted_work=''
         for number in work.split("|"):
             deleted_work = deleted_work + str(-1*int(number))
         log.work = deleted_work
         self._delete(context, log)
     elif operation == "create":
         brand = payload_list[4]
         model = payload_list[5]
         description = payload_list[6]
         log.mileage = 0
         log.work = '0'
         log.description = description
         log.brand = brand
         log.model = model
         log.timestamp = str(time.strftime("%Y-%m-%d %H:%M"))
         self._create(context,log)
     else:
         LOGGER.info("Unhandled action. Operation should be add, delete, create or history")
Beispiel #5
0
async def create_asset(request):

    required_fields = [
        "user_id", "password", "file_name", "file_hash", "base64_file_bytes"
    ]

    common.validate_fields(required_fields, request.json)

    file_exist = await asset_query.fetch_info_by_filehash(
        request.app.config.DB_CONN, request.json["file_hash"])

    if file_exist:
        raise ApiInternalError("file already exist. Try again later")

    file_bytes = base64.b64decode(request.json["base64_file_bytes"])

    mnemonic, address, account = await accounts_utils.get_account_details(
        request)

    childkey_index = common.gen_childkey_index()

    child_private_key, child_public_key = await remote_api.get_child_key(
        mnemonic, childkey_index)

    private_hex_key, public_hex_key = await remote_api.get_child_key(
        mnemonic, request.app.config.ROOT_KEY_INDEX)

    private_key = Secp256k1PrivateKey.from_hex(private_hex_key)

    signer = CryptoFactory(request.app.config.CONTEXT).new_signer(private_key)
    public_key = signer.get_public_key().as_hex()

    aes_key = encryption.generate_aes_key(16)

    ciphertext, tag, nonce = encryption.aes_encrypt(aes_key, file_bytes)

    ciphertext = b"".join([tag, ciphertext, nonce])

    secrets = binascii.hexlify(ciphertext)

    struct = {
        "file_hash": request.json["file_hash"],
        "file_name": request.json["file_name"],
        "file_cipher_hex": secrets.decode()
    }

    s3_key = amazon_s3.generate_s3_key(request.json["user_id"],
                                       request.json["file_name"])
    s3_url = amazon_s3.store_s3(request, s3_key, request.json["user_id"],
                                struct)
Beispiel #6
0
async def generate_asset_address(request):

    required_fields = ["user_id", "password"]

    common.validate_fields(required_fields, request.json)

    mnemonic, address, account = await accounts_utils.get_account_details(
        request)
    # print(type(account))
    childkey_index = common.gen_childkey_index()

    if "keys" in account.keys():
        while childkey_index in account["keys"]:
            childkey_index = common.gen_childkey_index()

    else:
        childkey_index = common.gen_childkey_index()

    child_private_key, child_public_key = await remote_api.get_child_key(
        mnemonic, childkey_index)

    private_hex_key, public_hex_key = await remote_api.get_child_key(
        mnemonic, request.app.config.ROOT_KEY_INDEX)

    private_key = Secp256k1PrivateKey.from_hex(private_hex_key)
    # private_key = request.app.config.CONTEXT.new_random_private_key()
    signer = CryptoFactory(request.app.config.CONTEXT).new_signer(private_key)
    public_key = signer.get_public_key().as_hex()

    batches, batch_id, batch_list_bytes = transaction_creation.create_empty_asset(
        txn_key=signer,
        batch_key=request.app.config.SIGNER,
        key_index=childkey_index,
        child_public_key=child_public_key,
        is_empty_asset=True)

    # print(batch_list_bytes)

    data = await messaging.send(batch_list_bytes, request)

    try:
        await messaging.wait_for_status(batch_id, 300, request)
    except (ApiBadRequest, ApiInternalError) as err:
        raise err

    token = common.generate_auth_token(request.app.config.SECRET_KEY,
                                       child_private_key, public_key)
    # print(token)
    return response.json({'authorization': token, 'key_index': childkey_index})
Beispiel #7
0
 def generate_signer(keyfile=None, pubkey_file=None):
     context = create_context('secp256k1')
     private_key = context.new_random_private_key()
     signer = None
     if keyfile:
         try:
             with open(keyfile, 'w') as fd:
                 fd.write(private_key.as_hex())
             with open(pubkey_file, 'w') as fd:
                 signer = CryptoFactory(context).new_signer(private_key)
                 fd.write(signer.get_public_key().as_hex())
         except OSError as err:
             raise ClientException(f'Failed to write private key: {err}')
     if not signer:
         signer = CryptoFactory(context).new_signer(private_key)
     return CryptoFactory(context).new_signer(private_key)
async def create_account(request):
    """Creates a new Account and corresponding authorization token"""
    required_fields = ['email', 'password']
    common.validate_fields(required_fields, request.json)

    private_key = request.app.config.CONTEXT.new_random_private_key()
    signer = CryptoFactory(request.app.config.CONTEXT).new_signer(private_key)
    public_key = signer.get_public_key().as_hex()

    auth_entry = _create_auth_dict(
        request, public_key, private_key.as_hex())
    await auth_query.create_auth_entry(request.app.config.DB_CONN, auth_entry)

    account = _create_account_dict(request.json, public_key)

    batches, batch_id = transaction_creation.create_account(
        txn_key=signer,
        batch_key=request.app.config.SIGNER,
        label=account.get('label'),
        description=account.get('description'))

    await messaging.send(
        request.app.config.VAL_CONN,
        request.app.config.TIMEOUT,
        batches)

    try:
        await messaging.check_batch_status(
            request.app.config.VAL_CONN, batch_id)
    except (ApiBadRequest, ApiInternalError) as err:
        await auth_query.remove_auth_entry(
            request.app.config.DB_CONN, request.json.get('email'))
        raise err

    token = common.generate_auth_token(
        request.app.config.SECRET_KEY,
        account.get('email'),
        public_key)

    return response.json(
        {
            'authorization': token,
            'account': account
        })
Beispiel #9
0
def search():
    keys = []
    for file in glob(f'{KEY_DIR}/*.priv'):
        try:
            with open(file) as f:
                contents = f.read().strip()
                private_key = Secp256k1PrivateKey.from_hex(contents)
                context = create_context('secp256k1')
                signer = CryptoFactory(context).new_signer(private_key)
                keys.append({
                    'name': os.path.splitext(os.path.basename(file))[0],
                    'pub_key': signer.get_public_key().as_hex()
                })
        except OSError:
            return {'error': f'Cannot read private key file {file}'}, 400
        except ParseError:
            return {
                'error': f'Cannot parse contents of private key file {file}'
            }, 400
    return {'keys': keys}
Beispiel #10
0
class IntkeyClient:
    def __init__(self, url, keyfile=None):
        self.url = url

        if keyfile is not None:
            try:
                with open(keyfile) as fd:
                    private_key_str = fd.read().strip()
                    fd.close()
            except OSError as err:
                raise IntkeyClientException(
                    'Failed to read private key: {}'.format(str(err)))

            try:
                private_key = Secp256k1PrivateKey.from_hex(private_key_str)
            except ParseError as e:
                raise IntkeyClientException(
                    'Unable to load private key: {}'.format(str(e)))

            self._signer = CryptoFactory(
                create_context('secp256k1')).new_signer(private_key)
            print(self._signer)

    def set(self, name, value, wait=None):
        return self._send_transaction('set', name, value, wait=wait)

    def inc(self, name, value, wait=None):
        return self._send_transaction('inc', name, value, wait=wait)

    def dec(self, name, value, wait=None):
        return self._send_transaction('dec', name, value, wait=wait)

    def mul(self, name, value, wait=None):
        return self._send_transaction('mul', name, value, wait=wait)

    def list(self):
        result = self._send_request("state?address={}".format(
            self._get_prefix()))

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            return [
                cbor.loads(base64.b64decode(entry["data"]))
                for entry in encoded_entries
            ]

        except BaseException:
            return None

    def show(self, name):
        address = self._get_address(name)

        result = self._send_request(
            "state/{}".format(address),
            name=name,
        )

        try:
            return cbor.loads(base64.b64decode(
                yaml.safe_load(result)["data"]))[name]

        except BaseException:
            return None

    def _get_status(self, batch_id, wait):
        try:
            result = self._send_request(
                'batch_statuses?id={}&wait={}'.format(batch_id, wait), )
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise IntkeyClientException(err)

    def _get_prefix(self):
        return _sha512('intkey'.encode('utf-8'))[0:6]

    def _get_address(self, name):
        prefix = self._get_prefix()
        game_address = _sha512(name.encode('utf-8'))[64:]
        return prefix + game_address

    def _send_request(self, suffix, data=None, content_type=None, name=None):
        if self.url.startswith("http://"):
            url = "{}/{}".format(self.url, suffix)
        else:
            url = "http://{}/{}".format(self.url, suffix)

        headers = {}

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise IntkeyKeyNotFoundException(
                    "No such key: {}".format(name))

            elif not result.ok:
                raise IntkeyClientException("Error {}: {}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise IntkeyClientException(
                'Failed to connect to REST API: {}'.format(err))

        except BaseException as err:
            raise IntkeyClientException(err)

        return result.text

    def _send_transaction(self, verb, name, value, wait=None):
        payload = cbor.dumps({
            'Verb': verb,
            'Name': name,
            'Value': value,
        })

        # Construct the address
        address = self._get_address(name)

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="intkey",
            family_version="1.0",
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2**64))).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=signature)

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request(
                "batches",
                batch_list.SerializeToString(),
                'application/octet-stream',
            )
            while wait_time < wait:
                status = self._get_status(
                    batch_id,
                    wait - int(wait_time),
                )
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request(
            "batches",
            batch_list.SerializeToString(),
            'application/octet-stream',
        )

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(header=header,
                      transactions=transactions,
                      header_signature=signature)
        return BatchList(batches=[batch])
from sawtooth_sdk.protobuf.transaction_pb2 import TransactionHeader
from sawtooth_sdk.protobuf.transaction_pb2 import Transaction
import sawtooth_sdk
from sawtooth_signing import create_context
from sawtooth_signing import CryptoFactory
from sawtooth_sdk.protobuf.batch_pb2 import BatchHeader
from sawtooth_sdk.protobuf.batch_pb2 import Batch
from sawtooth_sdk.protobuf.batch_pb2 import BatchList

#Creates a signer who will sign the tx and validate
#its identity in front of the validator
context = create_context('secp256k1')
private_key = context.new_random_private_key()

signer = CryptoFactory(context).new_signer(private_key)
print("SIGNER ES: {}".format(signer.get_public_key().as_hex()))

#Checks for correct amount of parameters
if len(sys.argv) != 3:
	print("Use: ./send_tx NumOfBatches NumOfTxPerBatch")
	sys.exit(1)

NUM_BATCHES = int(sys.argv[1])
NUM_TX_PER_BATCH = int(sys.argv[2])

#Generate the payload of the tx
#Every family has a structure to follow
#Uses the cbor format

N = 10
    def apply(self, transaction, context):

        header = transaction.header
        payload_cbor = transaction.payload
        payload = cbor.loads(payload_cbor)
        listo = payload.split(',')

        if listo[0] == "CREATE":

            amount = listo[2]
            code = listo[3]
            image = listo[1]
            aadhar = listo[4]
            account_number = listo[5]
            name = listo[6]
            message = listo[7]
            key = listo[8]

            LOGGER.info("\n the code is " + code)
            wallet_address = self._get_wallet_address(code)
            LOGGER.info("\n THe code is " + code)
            stop_encode = payload.encode('utf-8')
            current_entry = context.get_state([wallet_address])
            if current_entry == []:
                LOGGER.info('Yes it can be done')
                addresses = context.set_state({wallet_address: stop_encode})
                if len(addresses) < 1:
                    raise InternalError("State Error")
            else:
                raise InternalError("Already built")

        elif listo[0] == "PAY":
            LOGGER.info("The length of the is" + str(len(listo)))
            amount = listo[2]
            image = listo[1]
            code = listo[3]
            pub_pos = listo[4]
            wallet_address = self._get_wallet_address(code)
            pub_pos = self._get_wallet_address(pub_pos)
            current_entry = context.get_state([wallet_address])
            current_entry2 = context.get_state([pub_pos])
            if current_entry == []:
                raise InvalidTransaction(
                    'No user with this key was registered')
            elif current_entry2 == []:
                raise InvalidTransaction(
                    'No user with this key pos was registered')
            else:
                splito = current_entry[0].data.decode('utf-8')
                splito2 = current_entry2[0].data.decode('utf-8')
                current_list = splito.split(',')
                current_list2 = splito2.split(',')
                LOGGER.info("The amount is " + amount)

                if int(current_list[2]) >= int(amount):
                    image1 = base64.b64decode(current_list[1])
                    image2 = base64.b64decode(image)
                    files = {'image': image1, 'image2': image2}
                    text = requests.post("http://finger-api:5000/",
                                         files=files).text
                    if text == "true":
                        current_list[2] = str(
                            int(current_list[2]) - int(amount))
                        temp = ','.join(current_list).encode('utf-8')
                        current_list2[2] = str(
                            int(current_list2[2]) + int(amount))
                        temp2 = ','.join(current_list2).encode('utf-8')
                        context.set_state({wallet_address: temp})
                        context.set_state({pub_pos: temp2})
                        key1 = current_list[8]
                        message1 = current_list[7]
                        key2 = current_list2[8]
                        message2 = current_list2[7]
                        file = open("priv.txt", 'r')
                        privkey = file.read()[0:-1]
                        file.close()
                        contexta = create_context('secp256k1')
                        pvkey = Secp256k1PrivateKey.from_hex(privkey)
                        signer = CryptoFactory(contexta).new_signer(pvkey)
                        signer_public_key = signer.get_public_key()
                        #LOGGER.debug("GUCHI "+key1+" "+message1+" "+signer_public_key)
                        dtg = contexta.verify(key1, str.encode(message1),
                                              signer_public_key)
                        btg = contexta.verify(key2, str.encode(message2),
                                              signer_public_key)

                        if dtg:
                            LOGGER.info("dtg")
                            requests.get(
                                "http://bank-api:8080/event?type=withdraw&amount={}&account_no={}"
                                .format(amount, current_list[5]))
                        if btg:
                            LOGGER.info("btg")
                            requests.get(
                                "http://bank-api:8080/event?type=deposit&amount={}&account_no={}"
                                .format(amount, current_list2[5]))
                        LOGGER.info("CURRENT AMOUNT IN CLIENT ADDRESS  " +
                                    context.get_state([wallet_address])
                                    [0].data.decode('utf-8').split(',')[2])

                    else:
                        raise InvalidTransaction('Fingerprint Does not Match')
                else:
                    raise InvalidTransaction('Less money in bankaccount')
        elif listo[0] == "ADD":

            LOGGER.info("IN the ADD")
            LOGGER.info("The length of the is" + str(len(listo)))

            code = listo[2]
            amount = listo[1]

            wallet_address = self._get_wallet_address(code)
            current_entry = context.get_state([wallet_address])
            if current_entry == []:
                LOGGER.info("This was invalid")
                raise InvalidTransaction(
                    'No user with this key was registered')
            else:
                splito = current_entry[0].data.decode('utf-8')
                current_list = splito.split(',')
                current_list[2] = str(int(current_list[2]) + int(amount))

                temp = ','.join(current_list).encode('utf-8')
                LOGGER.debug("the amount is " + amount)
                LOGGER.info("the amount is " + amount)
                context.set_state({wallet_address: temp})
                LOGGER.info("CURRENT AMOUNT IN CLIENT ADDRESS  " +
                            context.get_state([wallet_address])[0].data.decode(
                                'utf-8').split(',')[2])
        elif listo[0] == "WITHD":

            code = listo[2]
            amount = listo[1]

            wallet_address = self._get_wallet_address(code)
            current_entry = context.get_state([wallet_address])
            if current_entry == []:
                LOGGER.info("This was invalid")
                raise InvalidTransaction(
                    'No user with this key was registered')
            else:
                splito = current_entry[0].data.decode('utf-8')
                current_list = splito.split(',')
                if int(amount) <= int(current_list[2]):
                    current_list[2] = str(int(current_list[2]) - int(amount))

                    temp = ','.join(current_list).encode('utf-8')
                    LOGGER.debug("the amount is " + amount)
                    LOGGER.info("the amount is " + amount)
                    context.set_state({wallet_address: temp})
                    LOGGER.info("CURRENT AMOUNT IN CLIENT ADDRESS  " +
                                context.get_state([wallet_address])
                                [0].data.decode('utf-8').split(',')[2])
                else:
                    raise InvalidTransaction('LOW BALANCE')
Beispiel #13
0
class HealthClient:
    """
    construct and send health transaction.
    """
    def __init__(self, base_url, work_path, keyfile=None):
        self._base_url = base_url
        self._work_path = work_path

        if keyfile is None:
            self._signer = None
            return

        try:
            with open(keyfile) as file_ptr:
                private_key_str = file_ptr.read().strip()
        except OSError as err:
            raise HealthException('Failed to read private key {}: {}'.format(
                keyfile, str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as parser_error:
            raise HealthException('Unable to load private key: {}'.format(
                str(parser_error)))

        self._signer = CryptoFactory(
            create_context('secp256k1')).new_signer(private_key)

    def code_analysis(self, github_url, github_user, commit_date, client_key):
        """
        send github url to code analysis to generate new health

        Args:
            github_url (str): commit url
            github_user (str): github user id
        """
        #get time
        txn_date = _get_date()

        #get host ip adress
        process_flag = 1
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(("8.8.8.8", 80))
        my_ip = s.getsockname()[0]
        s.close()

        if my_ip == client_key[6:].split(':')[0]:
            process_flag = 0

        #if process is zero then check latest health
        #get latest health
        if process_flag == 0:
            result = self._send_request("transactions")
            transactions = {}
            try:
                encoded_entries = yaml.safe_load(result)["data"]
                for entry in encoded_entries:
                    #try to pull the specific transaction, if the format is not right
                    #the transaction corresponds to the consesus family
                    try:
                        transaction_type = base64.b64decode(
                            entry["payload"]).decode().split(',')[0]
                        if transaction_type == "health":
                            transactions[
                                entry["header_signature"]] = base64.b64decode(
                                    entry["payload"])
                            #assuming we got all transactions in order
                            break
                    except:
                        pass
            except BaseException:
                return None

            for entry in transactions:
                previous_commit = transactions[entry].decode().split(',')[4]
                if previous_commit == github_url:
                    #if the commit url of the previous health is equal to the new commit url
                    #then ignore the transaction
                    process_flag == 1
                break

        #we got a new commit, calculate health
        if process_flag == 0:
            work_path = os.path.dirname(
                os.path.dirname(
                    os.path.dirname(os.path.dirname(
                        os.path.realpath(__file__)))))
            sawtooth_home = work_path + "/results"

            #get repo path
            conf_file = work_path + '/etc/.repo'
            try:
                with open(conf_file, 'r') as path:
                    repo_path = path.read()
                path.close()
            except IOError as error:
                raise HealthException(
                    "Unable to open configuration file {}".format(error))

            repo_path = repo_path.replace(
                '\n', ''
            ) + '/CodeAnalysis/SourceMeter_Interface/src/sourceMeterWrapper.py'
            print('CALLING ANLSYIS WITH:',
                  ['python2.7', repo_path, github_url, sawtooth_home])
            subprocess.check_output(
                ['python2.7', repo_path, github_url, sawtooth_home])

            for filename in os.listdir(sawtooth_home):
                csv_path = sawtooth_home + '/' + filename
                break

            try:
                suse_config = _get_config_file()
                suse_config = suse_config["code_smells"]
                health = calculate_health(suse_config=suse_config,
                                          csv_path=csv_path)

                if health > 0:
                    do_suse(url=self._base_url,
                            health=health,
                            github_id=github_user)

                response = self._send_health_txn(txn_type='health',
                                                 txn_id=github_user,
                                                 data=str(health),
                                                 state='processed',
                                                 url=github_url,
                                                 client_key=client_key,
                                                 txn_date=txn_date)
                return response
            except Exception as error:
                return error

    def commit(self, commit_url, github_id, commit_date, client_key):
        """
        Send commit url to code analysis

        Args:
            commit_url (str), git url to do a pull
            github_id (str), user github ID
        """

        response = self._send_health_txn(txn_type='commit',
                                         txn_id=github_id,
                                         data=commit_url,
                                         state='new',
                                         url=self._base_url,
                                         client_key=client_key,
                                         txn_date=commit_date)

        return response

    def list(self, txn_type=None, limit=None):
        """
        list all transactions.
        Args:
            txn_type (str), transaction type
            limit (int), number of transactions to pull
        """
        #pull all transactions of health family
        if limit is None:
            result = self._send_request("transactions")
        else:
            result = self._send_request("transactions?limit={}".format(limit))
        transactions = {}
        try:
            encoded_entries = yaml.safe_load(result)["data"]
            if txn_type is None:
                for entry in encoded_entries:
                    transactions[entry["header_signature"]] = base64.b64decode(
                        entry["payload"])

            else:
                for entry in encoded_entries:
                    #try to pull the specific transaction, if the format is not right
                    #the transaction corresponds to the consesus family
                    try:
                        transaction_type = base64.b64decode(
                            entry["payload"]).decode().split(',')[0]
                        if transaction_type == txn_type:
                            transactions[
                                entry["header_signature"]] = base64.b64decode(
                                    entry["payload"])
                    except:
                        pass
            return transactions
        except BaseException:
            return None

    def _get_prefix(self):
        """
        get health family address prefix
        """
        return _sha512('health'.encode('utf-8'))[0:6]

    def _get_address(self, txn_id):
        """
        get transaction address

        Args:
            id (str): trasaction id
        """
        health_prefix = self._get_prefix()
        health_address = _sha512(txn_id.encode('utf-8'))[0:64]
        return health_prefix + health_address

    def _send_request(self,
                      suffix,
                      data=None,
                      content_type=None,
                      auth_user=None,
                      auth_password=None):
        """
        send request to health processor`
        """
        if self._base_url.startswith("http://"):
            url = "{}/{}".format(self._base_url, suffix)
        else:
            url = "http://{}/{}".format(self._base_url, suffix)

        headers = {}
        if auth_user is not None:
            auth_string = "{}:{}".format(auth_user, auth_password)
            b64_string = b64encode(auth_string.encode()).decode()
            auth_header = 'Basic {}'.format(b64_string)
            headers['authorization'] = auth_header

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise HealthException("No such transaction")
            elif not result.ok:
                raise HealthException("Error {}:{}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise HealthException('Failed to connect to {}:{}'.format(
                url, str(err)))

        except BaseException as err:
            raise HealthException(err)

        return result.text

    def _send_health_txn(self,
                         txn_type=None,
                         txn_id=None,
                         data=None,
                         state=None,
                         url=None,
                         client_key=None,
                         txn_date=None):
        """
        serialize payload and create header transaction

        Args:
            type (str):    type of transaction
            id (str):      asset id, will depend on type of transaction
            data (object): transaction data
            state (str):   all transactions must have a state
        """
        #serialization is just a delimited utf-8 encoded strings
        payload = ",".join(
            [txn_type, txn_id, data, state, url, client_key,
             str(txn_date)]).encode()

        #pprint("payload: {}".format(payload))

        #construct the address
        address = self._get_address(txn_id)

        #construct header

        key_path = os.path.expanduser('~')
        key_path = key_path + "/.sawtooth/keys"
        print(key_path)
        print("hash:" + self._signer.get_public_key().as_hex())
        for pub_file in os.listdir(key_path):
            if "root.pub" in pub_file:
                print("File:" + pub_file)
                line = open(key_path + '/' + pub_file, 'r')
                key = line.read().strip()
                line.close()
                print("user key: " + key)
                break

        header = TransactionHeader(
            signer_public_key=str(key),
            family_name="health",
            family_version="0.1",
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2**64))).SerializeToString()

        signature = self._signer.sign(header)

        #create transaction
        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=signature)

        #create batch list, suserum policy: one transaction per batch
        batch_list = self._create_batch_list([transaction])

        return self._send_request("batches", batch_list.SerializeToString(),
                                  'application/octet-stream')

    def _create_batch_list(self, transactions):
        """
        Create the list of batches that the client will send to the REST API

        Args:
            transactions (transaction): transaction(s) included in the batch

        Returns:
            BatchList: a list of batches to send to the REST API
        """
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(header=header,
                      transactions=transactions,
                      header_signature=signature)

        return BatchList(batches=[batch])
class Transactor:
    def __init__(self, name, rest_endpoint):
        """
        Args:
            name (str): An identifier for this Transactor
            rest_endpoint (str): The rest api that this Transactor will
                communicate with.
        """

        self.name = name
        self._rest_endpoint = rest_endpoint \
            if rest_endpoint.startswith("http://") \
            else "http://{}".format(rest_endpoint)
        with open('/root/.sawtooth/keys/{}.priv'.format(name)) as priv_file:
            private_key = Secp256k1PrivateKey.from_hex(
                priv_file.read().strip('\n'))
        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(private_key)
        self._factories = {}
        self._client = RestClient(url=self._rest_endpoint)

        self._add_transaction_family_factory(Families.INTKEY)
        self._add_transaction_family_factory(Families.XO)

    @property
    def public_key(self):
        return self._signer.get_public_key().as_hex()

    def _add_transaction_family_factory(self, family_name):
        """Add a MessageFactory for the specified family.

        Args:
            family_name (Families): One of the Enum values representing
                transaction families.
        """

        family_config = FAMILY_CONFIG[family_name]
        self._factories[family_name] = MessageFactory(
            family_name=family_config['family_name'],
            family_version=family_config['family_version'],
            namespace=family_config['namespace'],
            signer=self._signer)

    def create_txn(self, family_name, batcher=None):
        unique_value = uuid4().hex[:20]
        encoder = TRANSACTION_ENCODER[family_name]['encoder']
        payload = encoder(
            TRANSACTION_ENCODER[family_name]['payload_func'](unique_value))

        address = TRANSACTION_ENCODER[family_name]['address_func'](
            unique_value)

        return self._factories[family_name].create_transaction(
            payload=payload,
            inputs=[address],
            outputs=[address],
            deps=[],
            batcher=batcher)

    def create_batch(self, family_name, count=1):
        transactions = [self.create_txn(family_name) for _ in range(count)]
        return self.batch_transactions(family_name, transactions=transactions)

    def batch_transactions(self, family_name, transactions):
        return self._factories[family_name].create_batch(
            transactions=transactions)

    def send(self, family_name, transactions=None):
        if not transactions:
            batch_list = self.create_batch(family_name)
        else:
            batch_list = self.batch_transactions(family_name=family_name,
                                                 transactions=transactions)

        self._client.send_batches(batch_list=batch_list)

    def set_public_key_for_role(self, policy, role, permit_keys, deny_keys):
        permits = ["PERMIT_KEY {}".format(key) for key in permit_keys]
        denies = ["DENY_KEY {}".format(key) for key in deny_keys]
        self._run_identity_commands(policy, role, denies + permits)

    def _run_identity_commands(self, policy, role, rules):
        subprocess.run([
            'sawtooth', 'identity', 'policy', 'create', '-k',
            '/root/.sawtooth/keys/{}.priv'.format(self.name), '--wait', '15',
            '--url', self._rest_endpoint, policy, *rules
        ],
                       check=True)
        subprocess.run([
            'sawtooth', 'identity', 'role', 'create', '-k',
            '/root/.sawtooth/keys/{}.priv'.format(self.name), '--wait', '15',
            '--url', self._rest_endpoint, role, policy
        ],
                       check=True)
Beispiel #15
0
class CaClient:
    def __init__(self, base_url, keyfile=None):

        self._base_url = base_url

        if keyfile is None:
            self._signer = None
            return

        try:
            with open(keyfile) as fd:
                private_key_str = fd.read().strip()
        except OSError as err:
            raise XoException(
                'Failed to read private key {}: {}'.format(
                    keyfile, str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as e:
            raise XoException(
                'Unable to load private key: {}'.format(str(e)))

        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(private_key)

    def create(self, csr, wait=None, auth_user=None, auth_password=None):
        return self._send_ca_txn(
            "create",
            value=csr,
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def init(self, pkey, wait=None, auth_user=None, auth_password=None):
        return self._send_ca_txn(
            "init",
            value=pkey,
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def simple(self, data, wait=None, auth_user=None, auth_password=None):
        return self._send_simple_txn(
            value=data,
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def get(self, serial: str, wait=None, auth_user=None, auth_password=None):
        return self._send_ca_txn(
            "get",
            value=serial,
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def status(self, serial: str, wait=None, auth_user=None, auth_password=None):
        return self._send_ca_txn(
            "status",
            value=serial,
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def revoke(self, serial: str, wait=None, auth_user=None, auth_password=None):
        return self._send_ca_txn(
            "revoke",
            value=serial,
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def _get_status(self, batch_id, wait, auth_user=None, auth_password=None):
        try:
            result = self._send_request(
                'batch_statuses?id={}&wait={}'.format(batch_id, wait),
                auth_user=auth_user,
                auth_password=auth_password)
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise XoException(err)

    def _get_prefix(self):
        return _sha512('ca_1'.encode('utf-8'))[:6]

    def _get_address(self, name):
        xo_prefix = self._get_prefix()
        game_address = _sha512(name.encode('utf-8'))[:64]
        return xo_prefix + game_address

    def _get_simple_address(self, data):
        prefix = hashlib.sha512('simple'.encode('utf-8')).hexdigest()[:6]
        address = hashlib.sha512(data.encode('utf-8')).hexdigest()[:64]
        return prefix + address

    def _send_request(self,
                      suffix,
                      data=None,
                      content_type=None,
                      name=None,
                      auth_user=None,
                      auth_password=None):
        if self._base_url.startswith("http://"):
            url = "{}/{}".format(self._base_url, suffix)
        else:
            url = "http://{}/{}".format(self._base_url, suffix)

        headers = {}
        if auth_user is not None:
            auth_string = "{}:{}".format(auth_user, auth_password)
            b64_string = b64encode(auth_string.encode()).decode()
            auth_header = 'Basic {}'.format(b64_string)
            headers['Authorization'] = auth_header

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise XoException("No such game: {}".format(name))

            elif not result.ok:
                raise XoException("Error {}: {}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise XoException(
                'Failed to connect to {}: {}'.format(url, str(err)))

        except BaseException as err:
            raise XoException(err)

        return result.text

    def _send_ca_txn(self,
                     action,
                     value="",
                     wait=None,
                     auth_user=None,
                     auth_password=None):
        # Serialization is just a delimited utf-8 encoded string
        payload = "|".join([action, datetime.datetime.utcnow().isoformat(), str(value)]).encode('utf-8')

        # Construct the address
        address = self._get_prefix()
        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="CA",
            family_version="1.0",
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2**64))
        ).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(
            header=header,
            payload=payload,
            header_signature=signature
        )

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request(
                "batches", batch_list.SerializeToString(),
                'application/octet-stream',
                auth_user=auth_user,
                auth_password=auth_password)
            while wait_time < wait:
                status = self._get_status(
                    batch_id,
                    wait - int(wait_time),
                    auth_user=auth_user,
                    auth_password=auth_password)
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request(
            "batches", batch_list.SerializeToString(),
            'application/octet-stream',
            auth_user=auth_user,
            auth_password=auth_password)

    def _send_simple_txn(self,
                         value="",
                         wait=None,
                         auth_user=None,
                         auth_password=None):
        # Serialization is just a delimited utf-8 encoded string
        payload = str(value).encode()

        # Construct the address
        address = self._get_simple_address('Simple Data Value 1')

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name='SIMPLE',
            family_version="1.0",
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2**64))
        ).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(
            header=header,
            payload=payload,
            header_signature=signature
        )

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request(
                "batches", batch_list.SerializeToString(),
                'application/octet-stream',
                auth_user=auth_user,
                auth_password=auth_password)
            while wait_time < wait:
                status = self._get_status(
                    batch_id,
                    wait - int(wait_time),
                    auth_user=auth_user,
                    auth_password=auth_password)
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request(
            "batches", batch_list.SerializeToString(),
            'application/octet-stream',
            auth_user=auth_user,
            auth_password=auth_password)

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures
        ).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(
            header=header,
            transactions=transactions,
            header_signature=signature)
        return BatchList(batches=[batch])

    def subscribe(self, event_name: str, is_write_to_file=False, file_name='certificate.pem'):
        subscription = EventSubscription(event_type="ca_1/{}".format(event_name))

        # Setup a connection to the validator
        ctx = zmq.Context()
        socket = ctx.socket(zmq.DEALER)
        socket.connect('tcp://127.0.0.1:4004')

        # Construct the request
        request = ClientEventsSubscribeRequest(
            subscriptions=[subscription]).SerializeToString()

        # Construct the message wrapper
        correlation_id = "123"  # This must be unique for all in-process requests
        msg = Message(
            correlation_id=correlation_id,
            message_type=Message.CLIENT_EVENTS_SUBSCRIBE_REQUEST,
            content=request)

        # Send the request
        socket.send_multipart([msg.SerializeToString()])

        # Receive the response
        resp = socket.recv_multipart()[-1]

        # Parse the message wrapper
        msg = Message()
        msg.ParseFromString(resp)

        # Validate the response type
        if msg.message_type != Message.CLIENT_EVENTS_SUBSCRIBE_RESPONSE:
            print("Unexpected message type")
            return

        # Parse the response
        response = ClientEventsSubscribeResponse()
        response.ParseFromString(msg.content)

        # Validate the response status
        if response.status != ClientEventsSubscribeResponse.OK:
            print("Subscription failed: {}".format(response.response_message))
            return

        resp = socket.recv_multipart()[-1]

        # Parse the message wrapper
        msg = Message()
        msg.ParseFromString(resp)

        # Validate the response type
        if msg.message_type != Message.CLIENT_EVENTS:
            print("Unexpected message type")
            return

        # Parse the response
        events = EventList()
        events.ParseFromString(msg.content)

        for event in events.events:
            if event.data is not None:
                if is_write_to_file:
                    write_to_file(file_name, event.data)
                else:
                    print(event.data)

        # Construct the request
        request = ClientEventsUnsubscribeRequest().SerializeToString()

        # Construct the message wrapper
        correlation_id = "124"  # This must be unique for all in-process requests
        msg = Message(
            correlation_id=correlation_id,
            message_type=Message.CLIENT_EVENTS_UNSUBSCRIBE_REQUEST,
            content=request)

        # Send the request
        socket.send_multipart([msg.SerializeToString()])

        # Receive the response
        resp = socket.recv_multipart()[-1]

        # Parse the message wrapper
        msg = Message()
        msg.ParseFromString(resp)

        # Validate the response type
        if msg.message_type != Message.CLIENT_EVENTS_UNSUBSCRIBE_RESPONSE:
            print("Unexpected message type")

        # Parse the response
        response = ClientEventsUnsubscribeResponse()
        response.ParseFromString(msg.content)

        # Validate the response status
        if response.status != ClientEventsUnsubscribeResponse.OK:
            print("Unsubscription failed: {}".format(response.response_message))

        # Close the connection to the validator
        socket.close()
Beispiel #16
0
class SimpleTestClient:

    def __init__(self, baseUrl):
        self._baseUrl = baseUrl
        privateKey = Secp256k1PrivateKey.from_hex(privateKeyStr)
        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(privateKey)
        self._publicKey = self._signer.get_public_key().as_hex()
        self.publicKey = self._signer.get_public_key().as_hex()

        self._address = _hash(FAMILY_NAME.encode('utf-8'))[0:6]
                        # _hash(self._publicKey.encode('utf-8'))[0:64]


    def wrap_and_send(self, data_dict):
        # rawPayload = action
        # for val in values:
        #     rawPayload = ",".join([rawPayload, str(val)])

        payload = json.dumps(data_dict).encode()

        address = self._address
        inputAddressList = [address]
        outputAddressList = [address]

        header = TransactionHeader(
            signer_public_key=self._publicKey,
            family_name=FAMILY_NAME,
            family_version="1.0",
            inputs=inputAddressList,
            outputs=outputAddressList,
            dependencies=[],
            payload_sha512=_hash(payload),
            batcher_public_key=self._publicKey,
            nonce=time.time().hex().encode()
        ).SerializeToString()

        transaction = Transaction(
            header=header,
            payload=payload,
            header_signature=self._signer.sign(header)
        )

        transactionList = [transaction]

        header = BatchHeader(
            signer_public_key=self._publicKey,
            transaction_ids=[txn.header_signature for txn in transactionList]
        ).SerializeToString()

        batch = Batch(
            header=header,
            transactions=transactionList,
            header_signature=self._signer.sign(header))

        batch_list = BatchList(batches=[batch])
        return self._send_to_restapi(
            "batches",
            batch_list.SerializeToString(),
            'application/octet-stream')

    def _send_to_restapi(self,
                      suffix,
                      data=None,
                      contentType=None):
        if self._baseUrl.startswith("http://"):
            url = "{}/{}".format(self._baseUrl, suffix)
        else:
            url = "http://{}/{}".format(self._baseUrl, suffix)

        headers = {}

        if contentType is not None:
            headers['Content-Type'] = contentType

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if not result.ok:
                print('服务器错误')

        except requests.ConnectionError as err:
            print('连接失败',err)
            # raise SimpleWalletException(
            #     'Failed to connect to {}: {}'.format(url, str(err)))

        except BaseException as err:
            # raise SimpleWalletException(err)
            print(err)
        return result.text


    def get_state(self):
        result = self._send_to_restapi(
            "state/{}".format(self._address))
        print(result)
        try:
            return base64.b64decode(yaml.safe_load(result)["data"])
        except BaseException:
            return None

    def get_block(self):
        result = requests.get(self._baseUrl+'/blocks')
        datas = result.json()['data']
        for data in datas:
            # print(data)
            payload = data['batches'][0]['transactions'][0]['payload']
            # print(payload)
            p = base64.b64decode(payload.encode()).decode()
            try:
                print(json.loads(p))
            except:
                pass
class CapBACClient:
    def __init__(self, url, keyfile=None):
        self.url = url

        if keyfile is not None:
            try:
                with open(keyfile) as fd:
                    private_key_str = fd.read().strip()
                    fd.close()
            except OSError as err:
                raise CapBACClientException(
                    'Failed to read private key: {}'.format(str(err)))

            try:
                private_key = Secp256k1PrivateKey.from_hex(private_key_str)
            except ParseError as e:
                raise CapBACClientException(
                    'Unable to load private key: {}'.format(str(e)))

            self._signer = CryptoFactory(
                create_context('secp256k1')).new_signer(private_key)

    # For each valid cli commands in _cli.py file
    # Add methods to:
    # 1. Do any additional handling, if required
    # 2. Create a transaction and a batch
    # 2. Send to rest-api

    def issue(self, token, is_root):

        try:
            token = json.loads(token)
        except:
            raise CapBACClientException('Invalid token: serialization failed')

        return self.issue_from_dict(token, is_root)

    def issue_from_dict(self,token, is_root):

        # check the formal validity of the incomplete token
        subset = set(CAPABILITY_FORMAT) - {'II','SI','VR'}
        if is_root: subset -= {'IC','SU'}

        _check_format(token,'capabiliy token',CAPABILITY_FORMAT,subset)

        for access_right in token['AR']:
            _check_format(access_right,'capability token: access right',ACCESS_RIGHT_FORMAT)

        # time interval logical check
        try:
            not_before = int(token['NB'])
            not_after  = int(token['NA'])
        except:
            raise CapBACClientException('Invalid capability: timestamp not a number')

        if not_before > not_after:
            raise CapBACClientException("Invalid capability: incorrect time interval")

        now = int(time.time())
        if now > not_after:
            raise CapBACClientException("Capability already expired")

        if is_root:
            token['IC'] = None
            token['SU'] = self._signer.get_public_key().as_hex()

        # add signature
        token= self.sign_dict(token)

        # now the token is complete

        payload = cbor.dumps({
            'AC': "issue",
            'OB': token
        })

        return self._send_transaction(payload, token['DE'])

    def revoke(self, token):

        try:
            token = json.loads(token)
        except:
            raise CapBACClientException('Invalid revocation token: serialization failed')

        return self.revoke_from_dict(token)

    def revoke_from_dict(self, token):

        # check the formal validity of the incomplete revocation token
        subset = set(REVOCATION_FORMAT) - {'II','SI','VR'}

        _check_format(token,'revocation token',REVOCATION_FORMAT,subset)

        # add signature
        token = self.sign_dict(token)

        # now the revocation token is complete

        payload = cbor.dumps({
            'AC': "revoke",
            'OB': token
        })

        return self._send_transaction(payload, token['DE'])

    def list(self,device):

        if len(device) > MAX_URI_LENGTH:
            raise CapBACClientException(
                'Invalid URI: max length exceeded, should be less than {}'
                .format(MAX_URI_LENGTH))

        result = self._send_request(
            "state?address={}".format(
                self._get_address(device)))

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            data_list = [
                cbor.loads(base64.b64decode(entry["data"]))
                for entry in encoded_entries
            ]

            return json.dumps({
                x:y[x] for y in data_list for x in y
            }, indent=4, sort_keys=True)

        except BaseException:
            return None

    def validate(self,token):

        try:
            token = json.loads(token)
        except:
            raise CapBACClientException('Invalid access token: serialization failed')

        return self.validate_from_dict(token)

    def validate_from_dict(self,token):

        _check_format(token,"access token",VALIDATION_FORMAT)

        # state retrival
        device = token['DE']
        result = self._send_request(
            "state?address={}".format(
                self._get_address(device)))

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            data_list =  [
                cbor.loads(base64.b64decode(entry["data"]))
                for entry in encoded_entries
            ]

            state = {x:y[x] for y in data_list for x in y}

        except BaseException:
            return None

        LOGGER.info('checking authorization')
        # check authorization
        capability = token['IC']

        if capability not in state:
            return False

        LOGGER.info('checking delegation chain')
        # delegation chain check
        now = int(time.time())
        resource = token['RE']
        action = token['AC']

        current_token = state[capability]
        parent = current_token['IC']
        while parent != None:
            if parent not in state:
                raise BaseException
            parent_token = state[parent]

            # check time interval
            if now >= int(parent_token['NA']):
                return False
            if now < int(parent_token['NB']):
                return False

            # check access rights
            if resource not in parent_token["AR"]:
                return False
            if action not in parent_token["AR"][resource]:
                return False

            # next
            current_token = parent_token
            parent = current_token['IC']

        LOGGER.info('checking signature')
        # check signature
        signature = token.pop('SI')
        if not create_context('secp256k1').verify(
            signature,
            str(cbor.dumps(token,sort_keys=True)).encode('utf-8'),
            Secp256k1PublicKey.from_hex(state[capability]['SU'])
            ):
            return False

        return True

    def sign(self, token):

        try:
            token = json.loads(token)
        except:
            raise CapBACClientException('Invalid token: serialization failed')

        token = self.sign_dict(token)
        return json.dumps(token)

    def sign_dict(self, token):

        # add version
        token['VR'] = FAMILY_VERSION

        # add issue time
        now = int(time.time())
        token['II'] = str(now)

        # add signature
        token_serialized = str(cbor.dumps(token,sort_keys=True)).encode('utf-8')
        token['SI'] = self._signer.sign(token_serialized)

        return token

    def _get_prefix(self):
        return _sha512(FAMILY_NAME.encode('utf-8'))[0:6]

    def _get_address(self, device):
        prefix = self._get_prefix()
        device_address = _sha512(device.encode('utf-8'))[64:]
        return prefix + device_address

    def _send_request(self,
                      suffix,
                      data=None,
                      contentType=None):
        if self.url.startswith("http://"):
            url = "{}/{}".format(self.url, suffix)
        else:
            url = "http://{}/{}".format(self.url, suffix)

        headers = {}

        if contentType is not None:
            headers['Content-Type'] = contentType

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if not result.ok:
                raise CapBACClientException("Error {}: {}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise CapBACClientException(
                'Failed to connect to {}: {}'.format(url, str(err)))

        except BaseException as err:
            raise CapBACClientException(err)

        return result.text

    def _send_transaction(self, payload, device):

        # Get the unique address for the device's tokens
        address = self._get_address(device)

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name=FAMILY_NAME,
            family_version=FAMILY_VERSION,
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=time.time().hex().encode()
        ).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(
            header=header,
            payload=payload,
            header_signature=signature
        )

        batch_list = self._create_batch_list([transaction])

        return self._send_request(
            "batches", batch_list.SerializeToString(),
            'application/octet-stream'
        )

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures
        ).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(
            header=header,
            transactions=transactions,
            header_signature=signature)
        return BatchList(batches=[batch])
class CarLoggerClient(object):
    '''Client car logger class.

    This supports create, add, delete, history functions.
    '''
    def __init__(self, baseUrl, private_key=None, vin=''):
        '''Initialize the client class.

           This is mainly getting the key pair and computing the address.
        '''

        self._baseUrl = baseUrl

        try:
            privateKey = Secp256k1PrivateKey.from_hex(private_key)
        except ParseError as err:
            raise Exception('Failed to load private key: {}'.format(str(err)))

        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(privateKey)

        self._publicKey = self._signer.get_public_key().as_hex()
        self.VIN = vin
        self._address = _hash(FAMILY_NAME.encode('utf-8'))[0:6] + \
            _hash(self.VIN.encode('utf-8'))[0:64]

    # For each valid cli command in _cli.py file,
    # add methods to:
    # 1. Do any additional handling, if required
    # 2. Create a transaction and a batch
    # 2. Send to rest-api

    def create(self, VIN, keyfile, work_date, brand, model, description):
        return self._wrap_and_send("create", VIN, keyfile, work_date, brand,
                                   model, description)

    def add(self, VIN, keyfile, work_date, work, km_status, description):
        return self._wrap_and_send("add", VIN, keyfile, work_date, work,
                                   km_status, description)

    def delete(self, VIN, keyfile, work_date, work, km_status, description):
        return self._wrap_and_send("delete", VIN, keyfile, work_date, work,
                                   km_status, description)

    def history(self):
        result = self._send_to_restapi("state/{}".format(self._address))
        try:
            return base64.b64decode(yaml.safe_load(result)["data"])

        except BaseException:
            return None

    def _send_to_restapi(self, suffix, data=None, contentType=None):
        '''Send a REST command to the Validator via the REST API.'''

        if self._baseUrl.startswith("http://"):
            url = "{}/{}".format(self._baseUrl, suffix)
        else:
            url = "http://{}/{}".format(self._baseUrl, suffix)

        headers = {}

        if contentType is not None:
            headers['Content-Type'] = contentType

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if not result.ok:
                raise Exception("Error {}: {}".format(result.status_code,
                                                      result.reason))

        except requests.ConnectionError as err:
            raise Exception('Failed to connect to {}: {}'.format(
                url, str(err)))

        except BaseException as err:
            raise Exception(err)

        return result.text

    def _wrap_and_send(self, action, *values):
        '''Create a transaction, then wrap it in a batch.
           Even single transactions must be wrapped into a batch.
        '''

        # Generate a csv utf-8 encoded string as payload
        rawPayload = action

        for val in values:
            rawPayload = ",".join([rawPayload, str(val)])

        payload = rawPayload.encode()

        # Construct the address where we'll store our state
        address = self._address
        inputAddressList = [address]
        outputAddressList = [address]

        # Create a TransactionHeader
        header = TransactionHeader(
            signer_public_key=self._publicKey,
            family_name=FAMILY_NAME,
            family_version="1.0",
            inputs=inputAddressList,
            outputs=outputAddressList,
            dependencies=[],
            payload_sha512=_hash(payload),
            batcher_public_key=self._publicKey,
            nonce=random.random().hex().encode()).SerializeToString()

        # Create a Transaction from the header and payload above
        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=self._signer.sign(header))

        transactionList = [transaction]

        # Create a BatchHeader from transactionList above
        header = BatchHeader(
            signer_public_key=self._publicKey,
            transaction_ids=[txn.header_signature
                             for txn in transactionList]).SerializeToString()

        # Create Batch using the BatchHeader and transactionList above
        batch = Batch(header=header,
                      transactions=transactionList,
                      header_signature=self._signer.sign(header))

        # Create a Batch List from Batch above
        batch_list = BatchList(batches=[batch])

        # Send batch_list to rest-api
        return self._send_to_restapi("batches", batch_list.SerializeToString(),
                                     'application/octet-stream')
class BattleshipClient:

    def __init__(self, base_url, keyfile, wait=None):
        """
        Member variables:
            _base_url
            _private_key
            _public_key
            _transaction_family
            _family_version
            _wait
        """
        self._base_url = base_url

        try:
            with open(keyfile) as fd:
                private_key_str = fd.read().strip()
        except OSError as err:
            raise IOError("Failed to read keys: {}.".format(str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as e:
            raise BattleshipException(
                'Unable to load private key: {}'.format(str(e)))

        self._signer = CryptoFactory(
            create_context('secp256k1')).new_signer(private_key)

        self._transaction_family = "battleship"
        self._family_version = "1.0"
        self._wait = wait

    def _send_battleship_txn(self, update):
        """The client needs to have the same
            defaults as the Transaction subclass
            before it is signed inside sendtxn
        """
        if 'Name' not in update:
            raise BattleshipException('Game name required')
        if 'Action' not in update:
            update['Action'] = None
        if 'Ships' not in update:
            update['Ships'] = None
        if update['Action'] == 'JOIN':
            if 'Board' not in update:
                update['Board'] = None
        if update['Action'] == 'FIRE':
            if 'Column' not in update:
                update['Column'] = None
            if 'Row' not in update:
                update['Row'] = None

        payload = json.dumps(update).encode()
        address = self._get_address(update['Name'])

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name=self._transaction_family,
            family_version=self._family_version,
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=self._sha512(payload),
            batcher_public_key=self.signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2**64))
        ).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(
            header=header,
            payload=payload,
            header_signature=signature
        )

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if self._wait and self._wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request(
                "batches", batch_list.SerializeToString(),
                'application/octet-stream'
            )
            while wait_time < self._wait:
                status = self._get_status(
                    batch_id,
                    self._wait - int(wait_time)
                )
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request(
            "batches", batch_list.SerializeToString(),
            'application/octet-stream')

    def create(self, name, ships):
        """ Create battleship game
        """
        update = {
            'Action': 'CREATE',
            'Name': name,
            'Ships': ships
        }

        return self._send_battleship_txn(update)

    def join(self, name, board):
        """ User joins battleship game
        """
        update = {
            'Action': 'JOIN',
            'Name': name,
            'Board': board
        }

        return self._send_battleship_txn(update)

    def fire(self, name, column, row, reveal_space, reveal_nonce):
        """ Fire at (column, row)
        """
        update = {
            'Action': 'FIRE',
            'Name': name,
            'Column': column,
            'Row': row
        }

        if reveal_space is not None:
            update['RevealSpace'] = reveal_space

        if reveal_nonce is not None:
            update['RevealNonce'] = reveal_nonce

        return self._send_battleship_txn(update)

    def list_games(self, auth_user=None, auth_password=None):
        prefix = self._get_prefix()

        result = self._send_request(
            "state?address={}".format(prefix),
            auth_user=auth_user,
            auth_password=auth_password
        )

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            ret = {}
            for entry in encoded_entries:
                d = json.loads(b64decode(entry["data"]).decode())
                for k, v in d.items():
                    ret[k] = v

            return ret

        except BaseException:
            return None

    def _sha512(self, data):
        return hashlib.sha512(data).hexdigest()

    def _get_prefix(self):
        return self._sha512(self._transaction_family.encode('utf-8'))[0:6]

    def _get_address(self, name):
        prefix = self._get_prefix()
        game_address = self._sha512(name.encode('utf-8'))[0:64]
        return prefix + game_address

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures
        ).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(
            header=header,
            transactions=transactions,
            header_signature=signature
        )
        return BatchList(batches=[batch])

    def _get_status(self, batch_id, wait):
        try:
            result = self._send_request(
                'batch_statuses?id={}&wait={}'.format(batch_id, wait))
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise BattleshipException(err)

    def _send_request(
            self, suffix, data=None,
            content_type=None, name=None, auth_user=None, auth_password=None):
        if self._base_url.startswith("http://"):
            url = "{}/{}".format(self._base_url, suffix)
        else:
            url = "http://{}/{}".format(self._base_url, suffix)

        headers = {}
        if auth_user is not None:
            auth_string = "{}:{}".format(auth_user, auth_password)
            b64_string = b64encode(auth_string.encode()).decode()
            auth_header = 'Basic {}'.format(b64_string)
            headers['Authorization'] = auth_header

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise BattleshipException("No such game: {}".format(name))

            elif not result.ok:
                raise BattleshipException("Error {}: {}".format(
                    result.status_code, result.reason))

        except BaseException as err:
            raise BattleshipException(err)

        return result.text
class Transactor(object):
    def __init__(self, name, rest_endpoint):
        """
        Args:
            name (str): An identifier for this Transactor
            rest_endpoint (str): The rest api that this Transactor will
                communicate with.
        """

        self.name = name
        self._rest_endpoint = rest_endpoint \
            if rest_endpoint.startswith("http://") \
            else "http://{}".format(rest_endpoint)
        with open('/root/.sawtooth/keys/{}.priv'.format(name)) as priv_file:
            private_key = Secp256k1PrivateKey.from_hex(
                priv_file.read().strip('\n'))
        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(private_key)
        self._factories = {}
        self._client = RestClient(url=self._rest_endpoint)

        self._add_transaction_family_factory(Families.INTKEY)
        self._add_transaction_family_factory(Families.XO)

    @property
    def public_key(self):
        return self._signer.get_public_key().as_hex()

    def _add_transaction_family_factory(self, family_name):
        """Add a MessageFactory for the specified family.

        Args:
            family_name (Families): One of the Enum values representing
                transaction families.
        """

        family_config = FAMILY_CONFIG[family_name]
        self._factories[family_name] = MessageFactory(
            family_name=family_config['family_name'],
            family_version=family_config['family_version'],
            namespace=family_config['namespace'],
            signer=self._signer)

    def create_txn(self, family_name, batcher=None):
        unique_value = uuid4().hex[:20]
        encoder = TRANSACTION_ENCODER[family_name]['encoder']
        payload = encoder(
            TRANSACTION_ENCODER[family_name]['payload_func'](unique_value))

        address = TRANSACTION_ENCODER[family_name]['address_func'](
            unique_value)

        return self._factories[family_name].create_transaction(
            payload=payload,
            inputs=[address],
            outputs=[address],
            deps=[],
            batcher=batcher)

    def create_batch(self, family_name, count=1):
        transactions = [self.create_txn(family_name) for _ in range(count)]
        return self.batch_transactions(family_name, transactions=transactions)

    def batch_transactions(self, family_name, transactions):
        return self._factories[family_name].create_batch(
            transactions=transactions)

    def send(self, family_name, transactions=None):
        if not transactions:
            batch_list = self.create_batch(family_name)
        else:
            batch_list = self.batch_transactions(
                family_name=family_name,
                transactions=transactions)

        self._client.send_batches(batch_list=batch_list)

    def set_public_key_for_role(self, policy, role, permit_keys, deny_keys):
        permits = ["PERMIT_KEY {}".format(key) for key in permit_keys]
        denies = ["DENY_KEY {}".format(key) for key in deny_keys]
        self._run_identity_commands(policy, role, denies + permits)

    def _run_identity_commands(self, policy, role, rules):
        subprocess.run(
            ['sawtooth', 'identity', 'policy', 'create',
             '-k', '/root/.sawtooth/keys/{}.priv'.format(self.name),
             '--wait', '15',
             '--url', self._rest_endpoint, policy, *rules],
            check=True)
        subprocess.run(
            ['sawtooth', 'identity', 'role', 'create',
             '-k', '/root/.sawtooth/keys/{}.priv'.format(self.name),
             '--wait', '15',
             '--url', self._rest_endpoint, role, policy],
            check=True)
class CookieJarClient(object):
    '''Client Cookie Jar class

    Supports "bake", "eat", and "count" functions.
    '''
    def __init__(self, base_url, key_file=None):
        '''Initialize the client class.

           This is mainly getting the key pair and computing the address.
        '''
        self._base_url = base_url

        if key_file is None:
            self._signer = None
            return

        try:
            with open(key_file) as key_fd:
                private_key_str = key_fd.read().strip()
        except OSError as err:
            raise Exception('Failed to read private key {}: {}'.format(
                key_file, str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as err:
            raise Exception( \
                'Failed to load private key: {}'.format(str(err)))

        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(private_key)
        self._public_key = self._signer.get_public_key().as_hex()

        # Address is 6-char TF prefix + hash of "mycookiejar"'s public key
        self._address = _hash(FAMILY_NAME.encode('utf-8'))[0:6] + \
            _hash(self._public_key.encode('utf-8'))[0:64]

    # For each CLI command, add a method to:
    # 1. Do any additional handling, if required
    # 2. Create a transaction and a batch
    # 2. Send to REST API
    def bake(self, amount):
        '''Bake amount cookies for the cookie jar.'''
        return self._wrap_and_send("bake", amount, wait=10)

    def eat(self, amount):
        '''Eat amount cookies from the cookie jar.'''
        try:
            ret_amount = self._wrap_and_send("eat", amount, wait=10)
        except Exception:
            raise Exception('Encountered an error during eat')
        return ret_amount

    def count(self):
        '''Count the number of cookies in the cookie jar.'''
        result = self._send_to_rest_api("state/{}".format(self._address))
        try:
            return base64.b64decode(yaml.safe_load(result)["data"])
        except BaseException:
            return None

    def _send_to_rest_api(self, suffix, data=None, content_type=None):
        '''Send a REST command to the Validator via the REST API.

           Called by count() &  _wrap_and_send().
           The latter caller is made on the behalf of bake() & eat().
        '''
        url = "{}/{}".format(self._base_url, suffix)
        print("URL to send to REST API is {}".format(url))

        headers = {}

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if not result.ok:
                raise Exception("Error {}: {}".format(result.status_code,
                                                      result.reason))
        except requests.ConnectionError as err:
            raise Exception('Failed to connect to {}: {}'.format(
                url, str(err)))
        except BaseException as err:
            raise Exception(err)

        return result.text

    def _wait_for_status(self, batch_id, wait, result):
        '''Wait until transaction status is not PENDING (COMMITTED or error).

           'wait' is time to wait for status, in seconds.
        '''
        if wait and wait > 0:
            waited = 0
            start_time = time.time()
            while waited < wait:
                result = self._send_to_rest_api(
                    "batch_statuses?id={}&wait={}".format(batch_id, wait))
                status = yaml.safe_load(result)['data'][0]['status']
                waited = time.time() - start_time

                if status != 'PENDING':
                    return result
            return "Transaction timed out after waiting {} seconds." \
               .format(wait)
        else:
            return result

    def _wrap_and_send(self, action, amount, wait=None):
        '''Create a transaction, then wrap it in a batch.

           Even single transactions must be wrapped into a batch.
           Called by bake() and eat().
        '''

        # Generate a CSV UTF-8 encoded string as the payload.
        raw_payload = ",".join([action, str(amount)])
        payload = raw_payload.encode()  # Convert Unicode to bytes

        # Construct the address where we'll store our state.
        # We just have one input and output address (the same one).
        input_and_output_address_list = [self._address]

        # Create a TransactionHeader.
        header = TransactionHeader(
            signer_public_key=self._public_key,
            family_name=FAMILY_NAME,
            family_version="1.0",
            inputs=input_and_output_address_list,
            outputs=input_and_output_address_list,
            dependencies=[],
            payload_sha512=_hash(payload),
            batcher_public_key=self._public_key,
            nonce=random.random().hex().encode()).SerializeToString()

        # Create a Transaction from the header and payload above.
        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=self._signer.sign(header))

        transaction_list = [transaction]

        # Create a BatchHeader from transaction_list above.
        header = BatchHeader(
            signer_public_key=self._public_key,
            transaction_ids=[txn.header_signature
                             for txn in transaction_list]).SerializeToString()

        # Create Batch using the BatchHeader and transaction_list above.
        batch = Batch(header=header,
                      transactions=transaction_list,
                      header_signature=self._signer.sign(header))

        # Create a Batch List from Batch above
        batch_list = BatchList(batches=[batch])
        batch_id = batch_list.batches[0].header_signature

        # Send batch_list to the REST API
        result = self._send_to_rest_api("batches",
                                        batch_list.SerializeToString(),
                                        'application/octet-stream')

        # Wait until transaction status is COMMITTED, error, or timed out
        return self._wait_for_status(batch_id, wait, result)
Beispiel #22
0
class SawtoothHelper:
    def __init__(self, base_url, validator_url=None, pk=None, context=None):
        self.base_url = base_url
        self.validator_url = validator_url if validator_url else f"{base_url}:4004"
        self.context = context if context else create_context("secp256k1")
        self.pk = pk if pk else self.context.new_random_private_key()
        self.signer = CryptoFactory(self.context).new_signer(self.pk)
        self.family_name = "DECODE_PETITION"
        self.family_version = "1.0"

    @property
    def private_key(self):
        return self.pk.secp256k1_private_key.serialize()

    def set_url(self, url):
        self.base_url = url

    def create_transaction(self, payload, family_name, family_version,
                           address):
        payload_bytes = cbor2.dumps(payload)

        txn_header = TransactionHeader(
            batcher_public_key=self.signer.get_public_key().as_hex(),
            inputs=[address],
            outputs=[address],
            dependencies=[],
            family_name=family_name,
            family_version=family_version,
            nonce=hex(randint(0, 2**64)),
            payload_sha512=sha512(payload_bytes).hexdigest(),
            signer_public_key=self.signer.get_public_key().as_hex(),
        ).SerializeToString()

        txn = Transaction(
            header=txn_header,
            header_signature=self.signer.sign(txn_header),
            payload=payload_bytes,
        )

        return [txn]

    def create_batch(self, transactions):
        batch_header = BatchHeader(
            signer_public_key=self.signer.get_public_key().as_hex(),
            transaction_ids=[txn.header_signature for txn in transactions],
        ).SerializeToString()

        batch = Batch(
            header=batch_header,
            header_signature=self.signer.sign(batch_header),
            transactions=transactions,
        )

        return BatchList(batches=[batch]).SerializeToString()

    def get_state(self, payload, address):
        petition_address = self.generate_address(self.family_name, payload)
        r = requests.get(f"{address}/state?address={petition_address}")
        return r.json()

    def get_batches(self, payload, address):
        state = self.get_state(payload, address)
        r = requests.get(f"{address}/blocks/{state['head']}")
        batches = r.json()["data"]["batches"]
        return batches

    def _post(self, payload, family_name, family_version, address):
        transactions = self.create_transaction(payload, family_name,
                                               family_version, address)
        batches = self.create_batch(transactions)
        response = requests.post(
            f"{self.base_url}",
            data=batches,
            headers={"Content-Type": "application/octet-stream"},
        )
        return response.json()

    def post(self, payload):
        address = self.generate_address(self.family_name, payload)
        return self._post(payload, self.family_name, self.family_version,
                          address)

    @staticmethod
    def generate_address(family_name, payload):
        namespace = sha512(family_name.encode("utf-8")).hexdigest()[0:6]
        petition = sha512(
            payload["petition_id"].encode("utf-8")).hexdigest()[-64:]
        return namespace + petition
Beispiel #23
0
class CodeSmellClient:
    """
    construct and send code smell transaction.
    """
    def __init__(self, base_url, work_path, keyfile=None):
        self._base_url = base_url
        self._work_path = work_path

        if keyfile is None:
            self._signer = None
            return

        try:
            with open(keyfile) as fileptr:
                private_key_str = fileptr.read().strip()
        except OSError as err:
            raise CodeSmellException(
                'Failed to read private key {}: {}'.format(keyfile, str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as error:
            raise CodeSmellException('Unable to load private key: {}'.format(
                str(error)))

        self._signer = CryptoFactory(
            create_context('secp256k1')).new_signer(private_key)

    def default(self):
        """
        load a defautl code smell configuration
        """

        #identify code_smell family configuration file
        conf_file = self._work_path + '/etc/.suse'
        response = ""

        if os.path.isfile(conf_file):
            try:
                with open(conf_file) as config:
                    raw_config = config.read()
            except IOError as error:
                raise CodeSmellException(
                    "Unable to load code smell family configuration file: {}".
                    format(error))

            #load toml config into a dict
            parsed_toml_config = toml.loads(raw_config)

            #get default code smells
            code_smells_config = parsed_toml_config['code_smells']
            #code_smells_config = parsed_toml_config
            """traverse dict and process each code smell
                nested for loop to procces level two dict."""
            for code_smells in code_smells_config.values():
                for name, metric in code_smells.items():
                    #send trasaction
                    response = self._send_code_smell_txn(
                        txn_type='code_smell',
                        txn_id=name,
                        data=str(metric[0]),  ## TODO: add weigth value
                        state='create')

            code_smells_config = parsed_toml_config['vote_setting']
            """traverse dict and process each code smell
                nested for loop to procces level two dict."""
            for name, metric in code_smells_config.items():
                #send transaction
                response = self._send_code_smell_txn(txn_type='code_smell',
                                                     txn_id=name,
                                                     data=str(metric[0]),
                                                     state='create')
        else:
            raise CodeSmellException(
                "Configuration File {} does not exists".format(conf_file))

        return response

    def list(self, txn_type=None, active_flag=None):
        """
        list all transactions.

        Args:
            type (str), asset that we want to list (code smells, proposals, votes)
        """
        #pull all transactions of code smell family
        result = self._send_request("transactions")

        transactions = {}
        try:
            encoded_entries = yaml.safe_load(result)["data"]
            if txn_type is None:
                for entry in encoded_entries:
                    transactions[entry["header_signature"]] = base64.b64decode(
                        entry["payload"])

            else:
                for entry in encoded_entries:
                    transaction_type = base64.b64decode(
                        entry["payload"]).decode().split(',')[0]
                    if transaction_type == txn_type:
                        transactions[
                            entry["header_signature"]] = base64.b64decode(
                                entry["payload"])

            if txn_type == 'proposal' and active_flag == 1:
                return sorted(transactions)
            else:
                return transactions
        except BaseException:
            return None

    def show(self, address):
        """
        list a specific transaction, based on its address

        Args:
            address (str), transaction's address
        """
        result = self._send_request("transactions/{}".format(address))

        transactions = {}
        try:
            encoded_entries = yaml.safe_load(result)["data"]
            transactions["payload"] = base64.b64decode(
                encoded_entries["payload"])
            transactions["header_signature"] = encoded_entries[
                "header_signature"]
            return transactions
        except BaseException:
            return None

    def propose(self, code_smells):
        """
        propose new metrics for the code smell families
        the function assumes that all code smells have been updated even if they don't

        Args:
            code_smells (dict), dictionary of code smells and metrics
        """
        #get code smell family address prefix
        code_smell_prefix = self._get_prefix()

        #check for an active proposal, transactions are return in sequential order.
        proposal_result = self._send_request(
            "state?address={}".format(code_smell_prefix))
        encoded_entries = yaml.safe_load(proposal_result)["data"]
        for entry in encoded_entries:
            #look for the first proposal transactiosn
            if base64.b64decode(
                    entry["data"]).decode().split(',')[0] == "proposal":
                last_proposal = base64.b64decode(
                    entry["data"]).decode().split(',')
                break
        try:
            if last_proposal[3] == "active":
                return "Invalid Operation, another proposal is Active"
        except BaseException:
            pass

        localtime = time.localtime(time.time())
        transac_time = str(localtime.tm_year) + str(localtime.tm_mon) + str(
            localtime.tm_mday)
        propose_date = str(transac_time)

        response = self._send_code_smell_txn(
            txn_id=_sha512(str(code_smells).encode('utf-8'))[0:6],
            txn_type='proposal',
            data=str(code_smells).replace(",", ";"),
            state='active',
            date=propose_date)

        return response

    def update_proposal(self, proposal_id, state):
        """
        update proposal state

        Args:
            proposal_id (str), proposal ID
            state (Str), new proposal ID
        """
        proposal = self.show(proposal_id)
        self._update_proposal(proposal, state)

    def _update_proposal(self, proposal, state):
        """
        update proposal, update state.

        Args:
            proposal (dict), proposal data
            sate (str), new proposal's state
        """
        localtime = time.localtime(time.time())
        transac_time = str(localtime.tm_year) + str(localtime.tm_mon) + str(
            localtime.tm_mday)
        propose_date = str(transac_time)

        response = self._send_code_smell_txn(txn_id=proposal[1],
                                             txn_type='proposal',
                                             data=proposal[2],
                                             state=state,
                                             date=propose_date)

        work_path = os.path.dirname(
            os.path.dirname(
                os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))
        conf_file = work_path + '/etc/.suse'

        if os.path.isfile(conf_file):
            try:
                with open(conf_file) as config:
                    raw_config = config.read()
            except IOError as error:
                raise CodeSmellException(
                    "Unable to load code smell family configuration file: {}".
                    format(error))
            #load toml config into a dict
            toml_config = toml.loads(raw_config)
        self._send_git_request(toml_config)

    def _send_git_request(self, toml_config):
        """
        send new code smell configuration to github

        Args:
            toml_config (dict): code smells to send
        """
        wrapper_json = {}
        wrapper_json["sender"] = "Sawtooth"
        wrapper_json["repo"] = "157484644"  ## TODO: update with dynamic repo
        wrapper_json["suse_file"] = toml_config
        data = json.dumps(wrapper_json)
        requests.post('http://129.108.7.2:3000', data=data)

    def update_config(self, proposal):
        """
        update code smell configuration metrics, after the proposal is accepted
        the configuration file needs to be updated.

        Args:
            toml_config (dict), current configuration
            proposal (str), proposal that contains new configuration
        """
        #get proposal payload
        proposal_payload = yaml.safe_load(proposal[2].replace(";", ","))

        work_path = os.path.dirname(
            os.path.dirname(
                os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))
        #identify code_smell family configuration file
        conf_file = work_path + '/etc/.suse'

        if os.path.isfile(conf_file):
            try:
                with open(conf_file) as config:
                    raw_config = config.read()
            except IOError as error:
                raise CodeSmellException(
                    "Unable to load code smell family configuration file: {}".
                    format(error))
            #load toml config into a dict
            toml_config = toml.loads(raw_config)
        """
        start by traversing the proposal,
        get the code smell and the metric
        """
        for proposal_key, proposal_metric in proposal_payload.items():
            tmp_type = ""
            """
            we don't know where on the toml file is the code smell,
            traverse the toml dictionary looking for the same code smell.
            """
            for code_type in toml_config["code_smells"]:
                """
                once you found the code smell, break the loop and return
                a pseudo location
                """
                if proposal_key in toml_config["code_smells"][code_type].keys(
                ):
                    tmp_type = code_type
                    break
            #update configuration
            toml_config["code_smells"][tmp_type][proposal_key][0] = int(
                proposal_metric)

        #save new configuration
        try:
            with open(conf_file, 'w+') as config:
                toml.dump(toml_config, config)
            #self._send_git_request(toml_config)
        except IOError as error:
            raise CodeSmellException(
                "Unable to open configuration file {}".format(error))

    def check_votes(self, proposal_id):
        """
        review the votes of a proposal

        Args:
            proposal_id (str), proposal id
        """
        result = self._send_request("transactions/{}".format(proposal_id))
        encoded_result = yaml.safe_load(result)["data"]
        proposal = base64.b64decode(
            encoded_result["payload"]).decode().split(',')
        proposal_id = proposal[1]
        transactions = self.list(txn_type='vote')
        votes = []
        for vote in transactions:
            #for all votes of proposal
            if transactions[vote].decode().split(',')[2] == proposal_id:
                #get vote and count, only accepted votes
                #if transactions[vote].decode().split(',')[3] == '1':
                votes.append(int(transactions[vote].decode().split(',')[3]))
        return votes

        ##################
        #NO NEED THE SERVER WILL HANDLE THIS
        #get treshold
        #identify code_smell family configuration file
        # conf_file = self._work_path + '/etc/.suse'
        #
        # if flag is not None:
        #     if os.path.isfile(conf_file):
        #         try:
        #             with open(conf_file) as config:
        #                 raw_config = config.read()
        #                 config.close()
        #         except IOError as error:
        #             raise CodeSmellException(
        #                 "Unable to load code smell family configuration file {}".format(error))
        #
        #         #load toml config into a dict
        #         parsed_toml_config = toml.loads(raw_config)
        #
        #         #get treshold
        #         code_smells_config = parsed_toml_config['vote_setting']
        #
        #         vote_treshold = int(code_smells_config['approval_treshold'])
        #
        #         if total_votes >= vote_treshold:
        #             self._update_config(parsed_toml_config, proposal)
        #             #you need this, you commented out to test the github stuff
        #             #self._update_proposal(proposal, "accepted")
        # else:
        #     return "Total votes (accepted): " + str(total_votes)

    def vote(self, proposal_id, vote):
        """
        vote to accept or reject a proposal

        Args:
            proposal_id (str), id of proposal
            vote (int), value of vote 1=accept, 0=reject
        """

        #verify active proposal
        result = self._send_request("transactions/{}".format(proposal_id))
        encoded_result = yaml.safe_load(result)["data"]
        proposal = base64.b64decode(
            encoded_result["payload"]).decode().split(',')
        if proposal[3] != 'active':
            return "Proposal not active"

        #verify double voting
        # proposal_id = proposal[1]
        # result = self._send_request("transactions")
        # encoded_entries = yaml.safe_load(result)["data"]
        # for entry in encoded_entries:
        #     transaction_type = base64.b64decode(entry["payload"]).decode().split(',')[0]
        #     if transaction_type == 'vote':
        #         if entry['header']['signer_public_key'] == self._signer.get_public_key().as_hex():
        #             return ("User already submitted a vote")

        #active proposal, record vote
        response = self._send_code_smell_txn(txn_id=str(
            random.randrange(1, 99999)),
                                             txn_type='vote',
                                             data=proposal[1],
                                             state=str(vote))

        # conf_file = '/home/mrwayne/Desktop/Susereum/Sawtooth/etc/.suse'
        #
        # if os.path.isfile(conf_file):
        #     try:
        #         with open(conf_file) as config:
        #             raw_config = config.read()
        #             config.close()
        #     except IOError as error:
        #         raise CodeSmellException(
        #             "Unable to load code smell family configuration file {}".format(error))
        #
        #     #load toml config into a dict
        # parsed_toml_config = toml.loads(raw_config)
        # self._send_git_request(parsed_toml_config)

        return response

    def send_config(self, config=None):
        """
        function to send an update configuration transaction to the chain
        after the code smell configuration is update al peers in the network
        must update the local configuration file.

        Args:
            config (dictionary), code smell configuration
        """
        #read .suse configuration file
        toml_config = self._get_config_file()
        print(toml_config)

    def _get_config_file(self):
        work_path = os.path.dirname(
            os.path.dirname(
                os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))

        #identify code_smell family configuration file
        conf_file = work_path + '/etc/.suse'

        if os.path.isfile(conf_file):
            try:
                with open(conf_file) as config:
                    raw_config = config.read()
            except IOError as error:
                raise CodeSmellException(
                    "Unable to load code smell family configuration file: {}".
                    format(error))
        #load toml config into a dict
        toml_config = toml.loads(raw_config)
        return toml_config

    def _get_status(self, batch_id, wait, auth_user=None, auth_password=None):
        try:
            result = self._send_request('batch_status?id={}&wait={}'.format(
                batch_id, wait),
                                        auth_user=auth_user,
                                        auth_password=auth_password)
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise CodeSmellException(err)

    def _get_prefix(self):
        """
        get code smell family address prefix
        """
        return _sha512('code-smell'.encode('utf-8'))[0:6]

    def _get_address(self, transaction_id):
        """
        get transaction address

        Args:
            id (str): trasaction id
        """
        code_smell_prefix = self._get_prefix()
        code_smell_address = _sha512(transaction_id.encode('utf-8'))[0:64]
        return code_smell_prefix + code_smell_address

    def _send_request(self,
                      suffix,
                      data=None,
                      content_type=None,
                      auth_user=None,
                      auth_password=None):
        """
        send request to code smell processor`
        """
        if self._base_url.startswith("http://"):
            url = "{}/{}".format(self._base_url, suffix)
        else:
            url = "http://{}/{}".format(self._base_url, suffix)

        headers = {}
        if auth_user is not None:
            auth_string = "{}:{}".format(auth_user, auth_password)
            b64_string = b64encode(auth_string.encode()).decode()
            auth_header = 'Basic {}'.format(b64_string)
            headers['authorization'] = auth_header

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise CodeSmellException("No such transaction")
            elif not result.ok:
                raise CodeSmellException("Error {}:{}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise CodeSmellException('Failed to connect to {}:{}'.format(
                url, str(err)))

        except BaseException as err:
            raise CodeSmellException(err)

        return result.text

    def _send_code_smell_txn(self,
                             txn_type=None,
                             txn_id=None,
                             data=None,
                             state=None,
                             date=None):
        """
        serialize payload and create header transaction

        Args:
            type (str):    type of transaction
            id (str):      asset id, will depend on type of transaction
            data (object): transaction data
            state (str):   all transactions must have a state
            wait (int):    delay to process transactions
        """
        #serialization is just a delimited utf-8 encoded strings
        if txn_type == 'proposal':
            payload = ",".join([txn_type, txn_id, data, state,
                                str(date)]).encode()
        else:
            payload = ",".join([txn_type, txn_id, data, state]).encode()

        pprint("payload: {}".format(
            payload))  ######################################## pprint

        #construct the address
        address = self._get_address(txn_id)

        #construct header`
        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="code-smell",
            family_version="0.1",
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2**64))).SerializeToString()

        signature = self._signer.sign(header)

        #create transaction
        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=signature)

        #create batch list, suserum policy: one transaction per batch
        batch_list = self._create_batch_list([transaction])

        return self._send_request("batches", batch_list.SerializeToString(),
                                  'application/octet-stream')

    def _create_batch_list(self, transactions):
        """
        Create the list of batches that the client will send to the REST API

        Args:
            transactions (transaction): transaction(s) included in the batch

        Returns:
            BatchList: a list of batches to send to the REST API
        """
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(header=header,
                      transactions=transactions,
                      header_signature=signature)

        return BatchList(batches=[batch])
Beispiel #24
0
class SawtoothClient(object):
    def __init__(self, url, keyfile=None):
        self.base_url = url

        if keyfile is not None:
            with open(keyfile) as fd:
                private_key_str = fd.read().strip()
                fd.close()

            sawtooth_signing_key = Secp256k1PrivateKey.from_hex(
                private_key_str)

            self._signer = CryptoFactory(
                create_context('secp256k1')).new_signer(sawtooth_signing_key)

    def add_net(self, network_id, payload, wait=None):
        address = make_network_address(network_id)
        return self._send_transaction(ActionTypes.ADD_NET.value,
                                      payload, [address],
                                      wait=wait)

    def _send_transaction(self, action, action_payload, addresses, wait=None):
        payload = cbor.dumps({'action': action, 'payload': action_payload})

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="billing-crdt",
            family_version="0.0.1",
            inputs=addresses,
            outputs=addresses,
            dependencies=[],
            payload_sha512=self._sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=self._nonce()).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=signature)

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request(
                "batches",
                batch_list.SerializeToString(),
                'application/octet-stream',
            )
            while wait_time < wait:
                status = self._get_status(
                    batch_id,
                    wait - int(wait_time),
                )
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request(
            "batches",
            batch_list.SerializeToString(),
            'application/octet-stream',
        )

    def _send_request(self, suffix, data=None, content_type=None, name=None):
        url = "{}/{}".format(self.base_url, suffix)
        headers = {}
        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if not result.ok:
                raise CrdtClientException(
                    "Error url={} name={} - {}: {}".format(
                        suffix, name, result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise CrdtClientException(
                'Failed to connect to REST API: {}'.format(err))

        except BaseException as err:
            raise CrdtClientException(err)

        return result.text

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(header=header,
                      transactions=transactions,
                      header_signature=signature)
        return BatchList(batches=[batch])

    @staticmethod
    def _sha512(data):
        return hashlib.sha512(data).hexdigest()

    @staticmethod
    def _nonce():
        return time.time().hex().encode()
Beispiel #25
0
class WalClient:
    def __init__(self, base_url, keyfile=None):
        self._base_url = base_url

        if keyfile is None:
            self._signer = None
            return

        try:
            with open(keyfile) as fd:
                private_key_str = fd.read().strip()

        except OSError as err:
            raise XoException('Failed to read private key {} : {}'.format(
                keyfile, str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)

        except ParseError as e:
            raise XoException('Unable to load priv key')

        self._signer = CryptoFactory(create_context('secp256k1')) \
         .new_signer(private_key)

    def create(self, name, pubkey, wait=None):

        return self._send_wal_txn(name, "create", pubkey=pubkey, wait=wait)

    def delete(self, name, pubkey, wait=None):
        return self._send_wal_txn(name, "delete", pubkey=pubkey, wait=wait)

    def prof(self, name, profile, wait=None):
        return self._send_wal_txn(name, "profile", pubkey=profile, wait=wait)

    def show(self, name):
        address = self._get_address(name)
        result = self._send_request("state/{}".format(address), name=name)

        try:
            return base64.b64decode(yaml.safe_load(result)["data"])
        except BaseException:
            return None

    def _get_status(self, batch_id, wait):
        try:
            result = self._send_request('batch_statuses?id={}&wait={}'.format(
                batch_id, wait))
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise XoException(err)

    def _get_prefix(self):
        return _sha512('wal'.encode('utf-8'))[0:6]

    def _get_address(self, name):
        wal_prefix = self._get_prefix()
        pair_address = _sha512(name.encode('utf-8'))[0:64]
        return wal_prefix + pair_address

    def _send_request(self, suffix, data=None, content_type=None, name=None):
        if self._base_url.startswith("http://"):
            url = "{}/{}".format(self._base_url, suffix)
        else:
            url = "http://{}/{}".format(self._base_url, suffix)

        headers = {}

        if content_type is not None:
            headers['Content-Type'] = content_type
        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)

            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise XoException("No such item: {}".format(name))

            elif not result.ok:
                raise XoException("Error {}:{}".format(result.status_code,
                                                       result.reason))

        except requests.ConnectionError as err:
            raise XoException('Failed to connect to {}:{}'.format(
                url, str(err)))

        except BaseException as err:
            raise XoException(err)
        return result.text

    def _send_wal_txn(self, name, action, pubkey, wait=None):

        payload = ",".join([name, action, pubkey]).encode()

        address = self._get_address(name)
        sec_address = self._get_address(pubkey)
        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="wal",
            family_version="1.0",
            inputs=[address, sec_address],
            outputs=[address, sec_address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=time.time().hex().encode()).SerializeToString()
        signature = self._signer.sign(header)

        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=signature)

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request("batches",
                                          batch_list.SerializeToString(),
                                          'application/octet-stream')
            while wait_time < wait:
                status = self._get_status(batch_id, wait - int(wait_time))
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request("batches", batch_list.SerializeToString(),
                                  'application/octet-stream')

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(header=header,
                      transactions=transactions,
                      header_signature=signature)
        return BatchList(batches=[batch])
Beispiel #26
0
class HwClient:
    def __init__(self, base_url, keyfile=None):

        self._base_url = base_url
        if keyfile is None:
            self._signer = None
            return

        try:
            with open(keyfile) as fd:
                private_key_str = fd.read().strip()
        except OSError as err:
            raise XoException('Failed to read private key {} : {}'.format(
                keyfile, str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as e:
            raise XoException('Unable to load priv key')

        self._signer = CryptoFactory(create_context('secp256k1')) \
         .new_signer(private_key)

    def create(self, name, cu_add=None, wait=None):
        return self._send_hw_txn(name,
                                 "create",
                                 cu_add=self._signer.get_public_key().as_hex(),
                                 nxt_add='no',
                                 wait=wait)

    def delete(self, name, wait=None):
        return self._send_hw_txn(name,
                                 "delete",
                                 cu_add=self._signer.get_public_key().as_hex(),
                                 nxt_add='no',
                                 wait=wait)

    def send(self, name, nxt_add, wait=None):
        return self._send_hw_txn(name,
                                 "send",
                                 cu_add=self._signer.get_public_key().as_hex(),
                                 nxt_add=nxt_add,
                                 wait=wait)

    def check(self, name, check_no, cu_add, wait=None):
        return self._send_hw_txn(
            name,
            check_no,
            cu_add=cu_add,
            nxt_add=self._signer.get_public_key().as_hex(),
            wait=wait)

    def show(self, name):
        address = self._get_address(name)
        result = self._send_request("state/{}".format(address), name=name)
        try:
            return base64.b64decode(yaml.safe_load(result)["data"])

        except BaseException:
            return None

    def _get_status(self, batch_id, wait):
        try:
            result = self._send_request('batch_statuses?id={}&wait={}'.format(
                batch_id, wait))
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise XoException(err)

    def _get_prefix(self):
        return _sha512('hw'.encode('utf-8'))[0:6]

    def _get_address(self, name):
        hw_prefix = self._get_prefix()
        item_address = _sha512(name.encode('utf-8'))[0:64]
        return hw_prefix + item_address

    def _get_key_address(self, name):
        wal_prefix = _sha512('wal'.encode('utf-8'))[0:6]
        key_address = _sha512(name.encode('utf-8'))[0:64]
        return wal_prefix + key_address

    def _send_request(self, suffix, data=None, content_type=None, name=None):
        if self._base_url.startswith("http://"):
            url = "{}/{}".format(self._base_url, suffix)
        else:
            url = "http://{}/{}".format(self._base_url, suffix)

        headers = {}

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)

            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise XoException("No such item: {}".format(name))

            elif not result.ok:
                raise XoException("Error {}:{}".format(result.status_code,
                                                       result.reason))

        except requests.ConnectionError as err:
            raise XoException('Failed to connect to {}:{}'.format(
                url, str(err)))

        except BaseException as err:
            raise XoException(err)

        return result.text

    def _send_hw_txn(self, name, action, cu_add, nxt_add, wait=None):

        payload = ",".join([name, action, cu_add, nxt_add]).encode()
        key_add = self._get_key_address(nxt_add)
        cli_add = self._get_key_address(cu_add)
        address = self._get_address(name)

        #for a transaction processor to access an address in the state database, we have to specify it in
        #inputs of the transaction header. For a transaction processor to change an element at an address,
        #we have to specify that address in outputs
        if key_add is not None:
            header = TransactionHeader(
                signer_public_key=self._signer.get_public_key().as_hex(),
                family_name="hw",
                family_version="1.0",
                inputs=[address, key_add, cli_add],
                outputs=[address],
                dependencies=[],
                payload_sha512=_sha512(payload),
                batcher_public_key=self._signer.get_public_key().as_hex(),
                nonce=time.time().hex().encode()).SerializeToString()

        else:
            header = TransactionHeader(
                signer_public_key=self._signer.get_public_key().as_hex(),
                family_name="hw",
                family_version="1.0",
                inputs=[address],
                outputs=[address],
                dependencies=[],
                payload_sha512=_sha512(payload),
                batcher_public_key=self._signer.get_public_key().as_hex(),
                nonce=time.time().hex().encode()).SerializeToString()

        signature = self._signer.sign(header)
        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=signature)

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request("batches",
                                          batch_list.SerializeToString(),
                                          'application/octet-stream')
            while wait_time < wait:
                status = self._get_status(batch_id, wait - int(wait_time))
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request("batches", batch_list.SerializeToString(),
                                  'application/octet-stream')

    #transactions are wrapped as batches. We wait some time to recieve any transactions to come by
    #If wait time is over , we complete the batch with the transactions recieved until that point and
    #wrap up the batch creation and push it into the validator rest-api

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(header=header,
                      transactions=transactions,
                      header_signature=signature)
        return BatchList(batches=[batch])
Beispiel #27
0
class Client:
    def __init__(self, url, keyfile=None):
        self.url = url

        if keyfile is not None:
            try:
                with open(keyfile) as fd:
                    private_key_str = fd.read().strip()
                    fd.close()
            except OSError as err:
                raise CrdtClientException(
                    'Failed to read private key: {}'.format(str(err)))

            try:
                private_key = Secp256k1PrivateKey.from_hex(private_key_str)
            except ParseError as e:
                raise CrdtClientException(
                    'Unable to load private key: {}'.format(str(e)))

            self._signer = CryptoFactory(
                create_context('secp256k1')).new_signer(private_key)

    def add_user(self, imsi, public_key, home_network, wait=None):
        action = ActionTypes.ADD_USER.value
        action_payload = cbor.dumps({
            'imsi': imsi,
            'pub_key': public_key,
            'home_net': home_network
        })
        address = make_user_address(imsi)
        return self._send_transaction(action,
                                      action_payload, [address],
                                      wait=wait)

    def list(self):
        result = self._send_request("state?address={}".format(
            self._get_prefix()))

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            return [
                cbor.loads(base64.b64decode(entry["data"]))
                for entry in encoded_entries
            ]

        except BaseException:
            return None

    def show_user(self, imsi):
        address = make_user_address(imsi)

        result = self._send_request(
            "state/{}".format(address),
            name=imsi,
        )

        try:
            print("Got to the load data part!")
            return cbor.loads(base64.b64decode(yaml.safe_load(result)["data"]))

        except BaseException:
            return None

    def _get_status(self, batch_id, wait):
        try:
            result = self._send_request(
                'batch_statuses?id={}&wait={}'.format(batch_id, wait), )
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise CrdtClientException(err)

    @staticmethod
    def _get_prefix():
        return _sha512('billing-crdt'.encode('utf-8'))[0:6]

    def _get_address(self, name):
        prefix = self._get_prefix()
        game_address = _sha512(name.encode('utf-8'))[64:]
        return prefix + game_address

    def _send_request(self, suffix, data=None, content_type=None, name=None):
        if self.url.startswith("http://"):
            url = "{}/{}".format(self.url, suffix)
        else:
            url = "http://{}/{}".format(self.url, suffix)

        headers = {}

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise CrdtClientException("No such key: {}".format(name))

            elif not result.ok:
                raise CrdtClientException("Error {}: {}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise CrdtClientException(
                'Failed to connect to REST API: {}'.format(err))

        except BaseException as err:
            raise CrdtClientException(err)

        return result.text

    def _send_transaction(self, action, action_payload, addresses, wait=None):
        payload = cbor.dumps({'action': action, 'payload': action_payload})

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="billing-crdt",
            family_version="0.0.1",
            inputs=addresses,
            outputs=addresses,
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=time.time().hex().encode()).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=signature)

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request(
                "batches",
                batch_list.SerializeToString(),
                'application/octet-stream',
            )
            while wait_time < wait:
                status = self._get_status(
                    batch_id,
                    wait - int(wait_time),
                )
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request(
            "batches",
            batch_list.SerializeToString(),
            'application/octet-stream',
        )

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(header=header,
                      transactions=transactions,
                      header_signature=signature)
        return BatchList(batches=[batch])
Beispiel #28
0
class IntkeyClient:
    def __init__(self, url, keyfile=None):
        self.url = url

        if keyfile is not None:
            try:
                with open(keyfile) as fd:
                    private_key_str = fd.read().strip()
                    fd.close()
            except OSError as err:
                raise IntkeyClientException(
                    'Failed to read private key: {}'.format(str(err)))

            try:
                private_key = Secp256k1PrivateKey.from_hex(private_key_str)
            except ParseError as e:
                raise IntkeyClientException(
                    'Unable to load private key: {}'.format(str(e)))

            self._signer = CryptoFactory(
                create_context('secp256k1')).new_signer(private_key)

    def set(self, name, value, wait=None):
        return self._send_transaction('set', name, value, wait=wait)

    def inc(self, name, value, wait=None):
        return self._send_transaction('inc', name, value, wait=wait)

    def dec(self, name, value, wait=None):
        return self._send_transaction('dec', name, value, wait=wait)

    def list(self):
        result = self._send_request(
            "state?address={}".format(
                self._get_prefix()))

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            return [
                cbor.loads(base64.b64decode(entry["data"]))
                for entry in encoded_entries
            ]

        except BaseException:
            return None

    def show(self, name):
        address = self._get_address(name)

        result = self._send_request("state/{}".format(address), name=name,)

        try:
            return cbor.loads(
                base64.b64decode(
                    yaml.safe_load(result)["data"]))[name]

        except BaseException:
            return None

    def _get_status(self, batch_id, wait):
        try:
            result = self._send_request(
                'batch_statuses?id={}&wait={}'.format(batch_id, wait),)
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise IntkeyClientException(err)

    def _get_prefix(self):
        return _sha512('intkey'.encode('utf-8'))[0:6]

    def _get_address(self, name):
        prefix = self._get_prefix()
        game_address = _sha512(name.encode('utf-8'))[64:]
        return prefix + game_address

    def _send_request(self, suffix, data=None, content_type=None, name=None):
        if self.url.startswith("http://"):
            url = "{}/{}".format(self.url, suffix)
        else:
            url = "http://{}/{}".format(self.url, suffix)

        headers = {}

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise IntkeyClientException("No such key: {}".format(name))

            elif not result.ok:
                raise IntkeyClientException("Error {}: {}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise IntkeyClientException(
                'Failed to connect to REST API: {}'.format(err))

        except BaseException as err:
            raise IntkeyClientException(err)

        return result.text

    def _send_transaction(self, verb, name, value, wait=None):
        payload = cbor.dumps({
            'Verb': verb,
            'Name': name,
            'Value': value,
        })

        # Construct the address
        address = self._get_address(name)

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="intkey",
            family_version="1.0",
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2**64))
        ).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(
            header=header,
            payload=payload,
            header_signature=signature
        )

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request(
                "batches", batch_list.SerializeToString(),
                'application/octet-stream',
            )
            while wait_time < wait:
                status = self._get_status(
                    batch_id,
                    wait - int(wait_time),
                )
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request(
            "batches", batch_list.SerializeToString(),
            'application/octet-stream',
        )

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures
        ).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(
            header=header,
            transactions=transactions,
            header_signature=signature)
        return BatchList(batches=[batch])
Beispiel #29
0
def generate_ecdsa_keys():
    context = create_context('secp256k1')
    sk = CryptoFactory(context).new_signer(context.new_random_private_key())
    return sk, sk.get_public_key().as_bytes()
Beispiel #30
0
class XoClient:
    def __init__(self, base_url, keyfile=None):

        self._base_url = base_url

        if keyfile is None:
            self._signer = None
            return

        try:
            with open(keyfile) as fd:
                private_key_str = fd.read().strip()
        except OSError as err:
            raise XoException(
                'Failed to read private key {}: {}'.format(
                    keyfile, str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as e:
            raise XoException(
                'Unable to load private key: {}'.format(str(e)))

        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(private_key)

    def create(self, name, wait=None, auth_user=None, auth_password=None):
        return self._send_xo_txn(
            name,
            "create",
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def delete(self, name, wait=None, auth_user=None, auth_password=None):
        return self._send_xo_txn(
            name,
            "delete",
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def take(self, name, space, wait=None, auth_user=None, auth_password=None):
        return self._send_xo_txn(
            name,
            "take",
            space,
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def list(self, auth_user=None, auth_password=None):
        xo_prefix = self._get_prefix()

        result = self._send_request(
            "state?address={}".format(xo_prefix),
            auth_user=auth_user,
            auth_password=auth_password)

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            return [
                base64.b64decode(entry["data"]) for entry in encoded_entries
            ]

        except BaseException:
            return None

    def show(self, name, auth_user=None, auth_password=None):
        address = self._get_address(name)

        result = self._send_request(
            "state/{}".format(address),
            name=name,
            auth_user=auth_user,
            auth_password=auth_password)
        try:
            return base64.b64decode(yaml.safe_load(result)["data"])

        except BaseException:
            return None

    def _get_status(self, batch_id, wait, auth_user=None, auth_password=None):
        try:
            result = self._send_request(
                'batch_statuses?id={}&wait={}'.format(batch_id, wait),
                auth_user=auth_user,
                auth_password=auth_password)
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise XoException(err)

    def _get_prefix(self):
        return _sha512('xo'.encode('utf-8'))[0:6]

    def _get_address(self, name):
        xo_prefix = self._get_prefix()
        game_address = _sha512(name.encode('utf-8'))[0:64]
        return xo_prefix + game_address

    def _send_request(self,
                      suffix,
                      data=None,
                      content_type=None,
                      name=None,
                      auth_user=None,
                      auth_password=None):
        if self._base_url.startswith("http://"):
            url = "{}/{}".format(self._base_url, suffix)
        else:
            url = "http://{}/{}".format(self._base_url, suffix)

        headers = {}
        if auth_user is not None:
            auth_string = "{}:{}".format(auth_user, auth_password)
            b64_string = b64encode(auth_string.encode()).decode()
            auth_header = 'Basic {}'.format(b64_string)
            headers['Authorization'] = auth_header

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise XoException("No such game: {}".format(name))

            elif not result.ok:
                raise XoException("Error {}: {}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise XoException(
                'Failed to connect to {}: {}'.format(url, str(err)))

        except BaseException as err:
            raise XoException(err)

        return result.text

    def _send_xo_txn(self,
                     name,
                     action,
                     space="",
                     wait=None,
                     auth_user=None,
                     auth_password=None):
        # Serialization is just a delimited utf-8 encoded string
        payload = ",".join([name, action, str(space)]).encode()

        # Construct the address
        address = self._get_address(name)

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="xo",
            family_version="1.0",
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=time.time().hex().encode()
        ).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(
            header=header,
            payload=payload,
            header_signature=signature
        )

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request(
                "batches", batch_list.SerializeToString(),
                'application/octet-stream',
                auth_user=auth_user,
                auth_password=auth_password)
            while wait_time < wait:
                status = self._get_status(
                    batch_id,
                    wait - int(wait_time),
                    auth_user=auth_user,
                    auth_password=auth_password)
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request(
            "batches", batch_list.SerializeToString(),
            'application/octet-stream',
            auth_user=auth_user,
            auth_password=auth_password)

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures
        ).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(
            header=header,
            transactions=transactions,
            header_signature=signature)
        return BatchList(batches=[batch])
Beispiel #31
0
class XoClient:
    def __init__(self, base_url, keyfile=None):

        self._base_url = base_url

        if keyfile is None:
            self._signer = None
            return

        try:
            with open(keyfile) as fd:
                private_key_str = fd.read().strip()
        except OSError as err:
            raise XoException('Failed to read private key {}: {}'.format(
                keyfile, str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError:
            try:
                private_key = Secp256k1PrivateKey.from_wif(private_key_str)
            except ParseError as e:
                raise XoException('Unable to load private key: {}'.format(
                    str(e)))

        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(private_key)

    def create(self, name, wait=None, auth_user=None, auth_password=None):
        return self._send_xo_txn(name,
                                 "create",
                                 wait=wait,
                                 auth_user=auth_user,
                                 auth_password=auth_password)

    def delete(self, name, wait=None, auth_user=None, auth_password=None):
        return self._send_xo_txn(name,
                                 "delete",
                                 wait=wait,
                                 auth_user=auth_user,
                                 auth_password=auth_password)

    def take(self, name, space, wait=None, auth_user=None, auth_password=None):
        return self._send_xo_txn(name,
                                 "take",
                                 space,
                                 wait=wait,
                                 auth_user=auth_user,
                                 auth_password=auth_password)

    def list(self, auth_user=None, auth_password=None):
        xo_prefix = self._get_prefix()

        result = self._send_request("state?address={}".format(xo_prefix),
                                    auth_user=auth_user,
                                    auth_password=auth_password)

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            return [
                base64.b64decode(entry["data"]) for entry in encoded_entries
            ]

        except BaseException:
            return None

    def show(self, name, auth_user=None, auth_password=None):
        address = self._get_address(name)

        result = self._send_request("state/{}".format(address),
                                    name=name,
                                    auth_user=auth_user,
                                    auth_password=auth_password)
        try:
            return base64.b64decode(yaml.safe_load(result)["data"])

        except BaseException:
            return None

    def _get_status(self, batch_id, wait, auth_user=None, auth_password=None):
        try:
            result = self._send_request('batch_statuses?id={}&wait={}'.format(
                batch_id, wait),
                                        auth_user=auth_user,
                                        auth_password=auth_password)
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise XoException(err)

    def _get_prefix(self):
        return _sha512('xo'.encode('utf-8'))[0:6]

    def _get_address(self, name):
        xo_prefix = self._get_prefix()
        game_address = _sha512(name.encode('utf-8'))[0:64]
        return xo_prefix + game_address

    def _send_request(self,
                      suffix,
                      data=None,
                      content_type=None,
                      name=None,
                      auth_user=None,
                      auth_password=None):
        if self._base_url.startswith("http://"):
            url = "{}/{}".format(self._base_url, suffix)
        else:
            url = "http://{}/{}".format(self._base_url, suffix)

        headers = {}
        if auth_user is not None:
            auth_string = "{}:{}".format(auth_user, auth_password)
            b64_string = b64encode(auth_string.encode()).decode()
            auth_header = 'Basic {}'.format(b64_string)
            headers['Authorization'] = auth_header

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise XoException("No such game: {}".format(name))

            elif not result.ok:
                raise XoException("Error {}: {}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise XoException('Failed to connect to {}: {}'.format(
                url, str(err)))

        except BaseException as err:
            raise XoException(err)

        return result.text

    def _send_xo_txn(self,
                     name,
                     action,
                     space="",
                     wait=None,
                     auth_user=None,
                     auth_password=None):
        # Serialization is just a delimited utf-8 encoded string
        payload = ",".join([name, action, str(space)]).encode()

        # Construct the address
        address = self._get_address(name)

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="xo",
            family_version="1.0",
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=time.time().hex().encode()).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=signature)

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request("batches",
                                          batch_list.SerializeToString(),
                                          'application/octet-stream',
                                          auth_user=auth_user,
                                          auth_password=auth_password)
            while wait_time < wait:
                status = self._get_status(batch_id,
                                          wait - int(wait_time),
                                          auth_user=auth_user,
                                          auth_password=auth_password)
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request("batches",
                                  batch_list.SerializeToString(),
                                  'application/octet-stream',
                                  auth_user=auth_user,
                                  auth_password=auth_password)

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(header=header,
                      transactions=transactions,
                      header_signature=signature)
        return BatchList(batches=[batch])
class Client():
    def __init__(self, base_url, private_key):
        self._base_url = base_url
        private_key = Secp256k1PrivateKey.from_hex(private_key)
        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(private_key)
        self._public_key = self._signer.get_public_key().as_hex()
        self._address = generate_address(self._public_key)

    def deposit(self, amount):
        return self.construct_payload_and_send("deposit", amount, 10)

    def withdraw(self, amount):
        return self.construct_payload_and_send("withdraw", amount, 10)

    def zero_balance(self, amount=0):
        return self.construct_payload_and_send("zero_balance", amount,  10)

    def check_balance(self):
        result = self.talk_to_validator("state/{}".format(self._address))
        try:
            return base64.b64decode(yaml.safe_load(result)["data"])
        except BaseException:
            return None

    def talk_to_validator(self, endpoint, payload=None, content_type=None):
        url = "{}/{}".format(self._base_url, endpoint)
        print("END POINT: {}".format(url))
        headers = {}
        if content_type is not None:
            headers['Content-Type'] = content_type
        try:
            if payload is not None:
                result = requests.post(url, headers=headers, data=payload)
            else:
                result = requests.get(url, headers=headers)

            if not result.ok:
                raise Exception("Error {}: {}".format(
                    result.status_code, result.reason))
        except requests.ConnectionError as err:
            raise Exception(
                'Failed to connect to {}: {}'.format(url, str(err)))
        except BaseException as err:
            raise Exception(err)
        return result.text

    def _wait_for_status(self, batch_id, wait, result):
        '''Wait until transaction status is not PENDING (COMMITTED or error).
           'wait' is time to wait for status, in seconds.
        '''
        if wait and wait > 0:
            waited = 0
            start_time = time.time()
            while waited < wait:
                result = self.talk_to_validator("batch_statuses?id={}&wait={}"
                                                .format(batch_id, wait))
                status = yaml.safe_load(result)['data'][0]['status']
                waited = time.time() - start_time

                if status != 'PENDING':
                    return result
            return "Transaction timed out after waiting {} seconds." \
                .format(wait)
        else:
            return result

    def construct_payload_and_send(self, action, amount, wait_time=None):
        raw_payload = ",".join([action, str(amount)])
        input_and_output_address_list = [self._address]
        print(self._address)
        header = TransactionHeader(
            signer_public_key=self._public_key,
            family_name=constants.FAMILY_NAME,
            family_version="1.0",
            inputs=input_and_output_address_list,
            outputs=input_and_output_address_list,
            dependencies=[],
            payload_sha512=generate_hash(raw_payload),
            batcher_public_key=self._public_key,
            nonce=random.random().hex().encode()
        ).SerializeToString()

        transaction = Transaction(
            header=header,
            payload=raw_payload.encode(),
            header_signature=self._signer.sign(header)
        )

        transaction_list = [transaction]
        header = BatchHeader(
            signer_public_key=self._public_key,
            transaction_ids=[txn.header_signature for txn in transaction_list]
        ).SerializeToString()

        batch = Batch(
            header=header,
            transactions=transaction_list,
            header_signature=self._signer.sign(header))

        batch_list = BatchList(batches=[batch])
        batch_id = batch_list.batches[0].header_signature
        print(batch_id)
        result = self.talk_to_validator("batches",
                                        batch_list.SerializeToString(),
                                        'application/octet-stream')
        # Wait until transaction status is COMMITTED, error, or timed out

        return self._wait_for_status(batch_id, wait_time, result)
Beispiel #33
0
private_key = context.new_random_private_key()
signer = CryptoFactory(context).new_signer(private_key)

#encode payload
#simple payload, name and owner
payload = {'action': 'create', 'asset': 'test', 'owner': 'test1'}

payload_bytes = cbor.dumps(payload)

#create transaction headers
txn_header_bytes = TransactionHeader(
    family_name='code-smell',
    family_version='0.1',
    inputs=['19d832'],
    outputs=['19d832'],
    signer_public_key=signer.get_public_key().as_hex(),
    # In this example, we're signing the batch with the same private key,
    # but the batch can be signed by another party, in which case, the
    # public key will need to be associated with that key.
    batcher_public_key=signer.get_public_key().as_hex(),
    # In this example, there are no dependencies.  This list should include
    # an previous transaction header signatures that must be applied for
    # this transaction to successfully commit.
    # For example,
    # dependencies=['540a6803971d1880ec73a96cb97815a95d374cbad5d865925e5aa0432fcf1931539afe10310c122c5eaae15df61236079abbf4f258889359c4d175516934484a'],
    dependencies=[],
    payload_sha512=sha512(payload_bytes).hexdigest()).SerializeToString()

#create transaction
signature = signer.sign(txn_header_bytes)
class HealthCareClient:

    def __init__(self, base_url, keyfile=None):

        self._base_url = base_url

        if keyfile is None:
            self._signer = None
            return

        try:
            with open(keyfile) as fd:
                private_key_str = fd.read().strip()
        except OSError as err:
            raise HealthCareException(
                'Failed to read private key {}: {}'.format(
                    keyfile, str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as e:
            raise HealthCareException(
                'Unable to load private key: {}'.format(str(e)))

        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(private_key)

    def create_clinic(self, name, wait=None, auth_user=None, auth_password=None):
        batch_key = txn_key = self._signer.get_public_key().as_hex()

        address = helper.make_clinic_address(clinic_pkey=txn_key)

        clinic = payload_pb2.CreateClinic(
            public_key=txn_key,
            name=name)

        payload = payload_pb2.TransactionPayload(
            payload_type=payload_pb2.TransactionPayload.CREATE_CLINIC,
            create_clinic=clinic)

        return self._send_healthcare_txn(txn_key, batch_key, [address], [address], payload,
                                         wait=wait,
                                         auth_user=auth_user,
                                         auth_password=auth_password)

    def create_doctor(self, name, surname, wait=None, auth_user=None, auth_password=None):
        batch_key = txn_key = self._signer.get_public_key().as_hex()

        address = helper.make_doctor_address(doctor_pkey=txn_key)

        doctor = payload_pb2.CreateDoctor(
            public_key=txn_key,
            name=name,
            surname=surname)

        payload = payload_pb2.TransactionPayload(
            payload_type=payload_pb2.TransactionPayload.CREATE_DOCTOR,
            create_doctor=doctor)

        return self._send_healthcare_txn(txn_key, batch_key, [address], [address], payload,
                                         wait=wait,
                                         auth_user=auth_user,
                                         auth_password=auth_password)

    def create_patient(self, name, surname, wait=None, auth_user=None, auth_password=None):
        batch_key = txn_key = self._signer.get_public_key().as_hex()

        address = helper.make_patient_address(patient_pkey=txn_key)

        patient = payload_pb2.CreatePatient(
            public_key=txn_key,
            name=name,
            surname=surname)

        payload = payload_pb2.TransactionPayload(
            payload_type=payload_pb2.TransactionPayload.CREATE_PATIENT,
            create_patient=patient)

        return self._send_healthcare_txn(txn_key, batch_key, [address], [address], payload,
                                         wait=wait,
                                         auth_user=auth_user,
                                         auth_password=auth_password)

    def add_claim(self, claim_id, patient_pkey, wait=None, auth_user=None,
                  auth_password=None):
        batch_key = txn_key = self._signer.get_public_key().as_hex()

        clinic_hex = helper.make_clinic_address(clinic_pkey=txn_key)
        claim_hex = helper.make_claim_address(claim_id=claim_id, clinic_pkey=txn_key)

        claim = payload_pb2.CreateClaim(
            claim_id=claim_id,
            clinic_pkey=txn_key,
            patient_pkey=patient_pkey,
        )

        payload = payload_pb2.TransactionPayload(
            payload_type=payload_pb2.TransactionPayload.CREATE_CLAIM,
            create_claim=claim)

        return self._send_healthcare_txn(txn_key, batch_key, [claim_hex, clinic_hex], [claim_hex], payload,
                                         wait=wait,
                                         auth_user=auth_user,
                                         auth_password=auth_password)

    def assign_doctor(self, claim_id, doctor_pkey, wait=None, auth_user=None,
                      auth_password=None):
        batch_key = txn_key = self._signer.get_public_key().as_hex()

        clinic_hex = helper.make_clinic_address(clinic_pkey=txn_key)
        claim_hex = helper.make_claim_address(claim_id=claim_id, clinic_pkey=txn_key)
        current_times_str = str(time.time())
        event_hex = helper.make_event_address(claim_id=claim_id, clinic_pkey=txn_key, event_time=current_times_str)

        assign = payload_pb2.ActionOnClaim(
            claim_id=claim_id,
            clinic_pkey=txn_key,
            description="Doctor pkey: {}, assigned to claim: {}".format(doctor_pkey, claim_hex),
            event_time=current_times_str)

        payload = payload_pb2.TransactionPayload(
            payload_type=payload_pb2.TransactionPayload.ASSIGN_DOCTOR,
            assign_doctor=assign)

        return self._send_healthcare_txn(txn_key, batch_key, [claim_hex, event_hex, clinic_hex], [event_hex], payload,
                                         wait=wait,
                                         auth_user=auth_user,
                                         auth_password=auth_password)

    def first_visit(self, claim_id, description, doctor_pkey, wait=None, auth_user=None,
                    auth_password=None):
        batch_key = txn_key = self._signer.get_public_key().as_hex()

        clinic_hex = helper.make_clinic_address(clinic_pkey=txn_key)
        claim_hex = helper.make_claim_address(claim_id=claim_id, clinic_pkey=txn_key)
        current_times_str = str(time.time())
        event_hex = helper.make_event_address(claim_id=claim_id, clinic_pkey=txn_key, event_time=current_times_str)

        first_visit = payload_pb2.ActionOnClaim(
            claim_id=claim_id,
            clinic_pkey=txn_key,
            description="Doctor pkey: {}, claim hex: {}, description: {}".format(doctor_pkey, claim_hex, description),
            event_time=current_times_str)

        payload = payload_pb2.TransactionPayload(
            payload_type=payload_pb2.TransactionPayload.FIRST_VISIT,
            first_visit=first_visit)

        return self._send_healthcare_txn(txn_key, batch_key, [claim_hex, event_hex, clinic_hex], [event_hex], payload,
                                         wait=wait,
                                         auth_user=auth_user,
                                         auth_password=auth_password)

    def pass_tests(self, claim_id, description, wait=None, auth_user=None,
                   auth_password=None):
        batch_key = txn_key = self._signer.get_public_key().as_hex()

        clinic_hex = helper.make_clinic_address(clinic_pkey=txn_key)
        claim_hex = helper.make_claim_address(claim_id=claim_id, clinic_pkey=txn_key)
        current_times_str = str(time.time())
        event_hex = helper.make_event_address(claim_id=claim_id, clinic_pkey=txn_key, event_time=current_times_str)

        pass_tests = payload_pb2.ActionOnClaim(
            claim_id=claim_id,
            clinic_pkey=txn_key,
            description=description,
            event_time=current_times_str)

        payload = payload_pb2.TransactionPayload(
            payload_type=payload_pb2.TransactionPayload.PASS_TESTS,
            pass_tests=pass_tests)

        return self._send_healthcare_txn(txn_key, batch_key, [claim_hex, event_hex, clinic_hex], [event_hex], payload,
                                         wait=wait,
                                         auth_user=auth_user,
                                         auth_password=auth_password)

    def attend_procedures(self, claim_id, description, wait=None, auth_user=None,
                          auth_password=None):
        batch_key = txn_key = self._signer.get_public_key().as_hex()

        clinic_hex = helper.make_clinic_address(clinic_pkey=txn_key)
        claim_hex = helper.make_claim_address(claim_id=claim_id, clinic_pkey=txn_key)
        current_times_str = str(time.time())
        event_hex = helper.make_event_address(claim_id=claim_id, clinic_pkey=txn_key, event_time=current_times_str)

        attend_procedures = payload_pb2.ActionOnClaim(
            claim_id=claim_id,
            clinic_pkey=txn_key,
            description=description,
            event_time=current_times_str)

        payload = payload_pb2.TransactionPayload(
            payload_type=payload_pb2.TransactionPayload.ATTEND_PROCEDURES,
            attend_procedures=attend_procedures)

        return self._send_healthcare_txn(txn_key, batch_key, [claim_hex, event_hex, clinic_hex], [event_hex], payload,
                                         wait=wait,
                                         auth_user=auth_user,
                                         auth_password=auth_password)

    def eat_pills(self, claim_id, description, wait=None, auth_user=None,
                  auth_password=None):
        batch_key = txn_key = self._signer.get_public_key().as_hex()

        clinic_hex = helper.make_clinic_address(clinic_pkey=txn_key)
        address = helper.make_claim_address(claim_id=claim_id, clinic_pkey=txn_key)
        current_times_str = str(time.time())
        event_hex = helper.make_event_address(claim_id=claim_id, clinic_pkey=txn_key, event_time=current_times_str)

        eat_pills = payload_pb2.ActionOnClaim(
            claim_id=claim_id,
            clinic_pkey=txn_key,
            description=description,
            event_time=current_times_str)

        payload = payload_pb2.TransactionPayload(
            payload_type=payload_pb2.TransactionPayload.EAT_PILLS,
            eat_pills=eat_pills)

        return self._send_healthcare_txn(txn_key, batch_key, [address, event_hex, clinic_hex], [event_hex], payload,
                                         wait=wait,
                                         auth_user=auth_user,
                                         auth_password=auth_password)

    def next_visit(self, claim_id, description, doctor_pkey, wait=None, auth_user=None,
                   auth_password=None):
        batch_key = txn_key = self._signer.get_public_key().as_hex()

        clinic_hex = helper.make_clinic_address(clinic_pkey=txn_key)
        claim_hex = helper.make_claim_address(claim_id=claim_id, clinic_pkey=txn_key)
        current_times_str = str(time.time())
        event_hex = helper.make_event_address(claim_id=claim_id, clinic_pkey=txn_key, event_time=current_times_str)

        next_visit = payload_pb2.ActionOnClaim(
            claim_id=claim_id,
            clinic_pkey=txn_key,
            description="Doctor pkey: {}, claim hex: {}, description: {}".format(doctor_pkey, claim_hex, description),
            event_time=current_times_str)

        payload = payload_pb2.TransactionPayload(
            payload_type=payload_pb2.TransactionPayload.NEXT_VISIT,
            next_visit=next_visit)

        return self._send_healthcare_txn(txn_key, batch_key, [claim_hex, event_hex, clinic_hex], [event_hex], payload,
                                         wait=wait,
                                         auth_user=auth_user,
                                         auth_password=auth_password)

    def list_claims(self, auth_user=None, auth_password=None):
        claim_list_prefix = helper.make_claim_list_address()

        result = self._send_request(
            "state?address={}".format(claim_list_prefix),
            auth_user=auth_user,
            auth_password=auth_password)
        orders = {}

        try:
            data = yaml.safe_load(result)["data"]
            if data is not None:
                for value in data:
                    dec_ord = base64.b64decode(value["data"])
                    o = payload_pb2.CreateClaim()
                    o.ParseFromString(dec_ord)
                    orders[value["address"]] = o

        except BaseException:
            pass

        return orders

    def list_patients(self, auth_user=None, auth_password=None):
        patient_list_prefix = helper.make_patient_list_address()

        result = self._send_request(
            "state?address={}".format(patient_list_prefix),
            auth_user=auth_user,
            auth_password=auth_password)
        patients = {}

        try:
            data = yaml.safe_load(result)["data"]
            if data is not None:
                for value in data:
                    dec_pt = base64.b64decode(value["data"])
                    pt = payload_pb2.CreatePatient()
                    pt.ParseFromString(dec_pt)
                    patients[value["address"]] = pt

        except BaseException:
            pass

        return patients

    def list_clinics(self, auth_user=None, auth_password=None):
        operator_list_prefix = helper.make_clinic_list_address()

        result = self._send_request(
            "state?address={}".format(operator_list_prefix),
            auth_user=auth_user,
            auth_password=auth_password)
        clinics = {}

        try:
            data = yaml.safe_load(result)["data"]
            if data is not None:
                for value in data:
                    dec_cl = base64.b64decode(value["data"])
                    cl = payload_pb2.CreateClinic()
                    cl.ParseFromString(dec_cl)
                    clinics[value["address"]] = cl

        except BaseException:
            pass

        return clinics

    def list_doctors(self, auth_user=None, auth_password=None):
        doctor_list_prefix = helper.make_doctor_list_address()

        result = self._send_request(
            "state?address={}".format(doctor_list_prefix),
            auth_user=auth_user,
            auth_password=auth_password)
        doctors = []

        try:
            data = yaml.safe_load(result)["data"]
            if data is not None:
                for value in data:
                    dec_dc = base64.b64decode(value["data"])
                    dc = payload_pb2.CreateDoctor()
                    dc.ParseFromString(dec_dc)
                    doctors.append(dc)

        except BaseException:
            pass

        return doctors

    def list_claim_details(self, claim_id, clinic_hex, auth_user=None, auth_password=None):
        claim_details_prefix = helper.make_event_list_address(claim_id=claim_id, clinic_pkey=clinic_hex)

        result = self._send_request(
            "state?address={}".format(claim_details_prefix),
            auth_user=auth_user,
            auth_password=auth_password)
        orders = {}

        try:
            data = yaml.safe_load(result)["data"]
            if data is not None:
                for value in data:
                    dec_ord = base64.b64decode(value["data"])
                    o = payload_pb2.ActionOnClaim()
                    o.ParseFromString(dec_ord)
                    orders[value["address"]] = o

        except BaseException:
            pass

        return orders

    def _send_request(self,
                      suffix,
                      data=None,
                      content_type=None,
                      name=None,
                      auth_user=None,
                      auth_password=None):
        if self._base_url.startswith("http://"):
            url = "{}/{}".format(self._base_url, suffix)
        else:
            url = "http://{}/{}".format(self._base_url, suffix)

        headers = {}
        if auth_user is not None:
            auth_string = "{}:{}".format(auth_user, auth_password)
            b64_string = base64.b64encode(auth_string.encode()).decode()
            auth_header = 'Basic {}'.format(b64_string)
            headers['Authorization'] = auth_header

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise HealthCareException("No such operator: {}".format(name))

            elif not result.ok:
                raise HealthCareException("Error {}: {}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise HealthCareException(
                'Failed to connect to {}: {}'.format(url, str(err)))

        except BaseException as err:
            raise HealthCareException(err)

        return result.text

    def _send_healthcare_txn(self, txn_key, batch_key, inputs, outputs, payload, wait,
                             auth_user, auth_password):

        txn_header_bytes, signature = self._transaction_header(txn_key, inputs, outputs, payload)

        txn = Transaction(
            header=txn_header_bytes,
            header_signature=signature,
            payload=payload.SerializeToString()
        )

        transactions = [txn]

        batch_header_bytes, signature = self._batch_header(batch_key, transactions)

        batch = Batch(
            header=batch_header_bytes,
            header_signature=signature,
            transactions=transactions
        )

        batch_list = BatchList(batches=[batch])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request(
                "batches", batch_list.SerializeToString(),
                'application/octet-stream',
                auth_user=auth_user,
                auth_password=auth_password)
            while wait_time < wait:
                status = self._get_status(
                    batch_id,
                    wait - int(wait_time),
                    auth_user=auth_user,
                    auth_password=auth_password)
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request(
            "batches", batch_list.SerializeToString(),
            'application/octet-stream',
            auth_user=auth_user,
            auth_password=auth_password)

    def _get_status(self, batch_id, wait, auth_user=None, auth_password=None):
        try:
            result = self._send_request(
                'batch_statuses?id={}&wait={}'.format(batch_id, wait),
                auth_user=auth_user,
                auth_password=auth_password)
            return yaml.safe_load(result)['data'][0]['status']
        except BaseException as err:
            raise HealthCareException(err)

    def _transaction_header(self, txn_key, inputs, outputs, payload):
        txn_header_bytes = TransactionHeader(
            family_name=helper.TP_FAMILYNAME,
            family_version=helper.TP_VERSION,
            inputs=inputs,
            outputs=outputs,
            signer_public_key=txn_key,  # signer.get_public_key().as_hex(),
            # In this example, we're signing the batch with the same private key,
            # but the batch can be signed by another party, in which case, the
            # public key will need to be associated with that key.
            batcher_public_key=txn_key,  # signer.get_public_key().as_hex(),
            # In this example, there are no dependencies.  This list should include
            # an previous transaction header signatures that must be applied for
            # this transaction to successfully commit.
            # For example,
            # dependencies=['540a6803971d1880ec73a96cb97815a95d374cbad5d865925e5aa0432fcf1931539afe10310c122c5eaae15df61236079abbf4f258889359c4d175516934484a'],
            dependencies=[],
            nonce=random.random().hex().encode(),
            payload_sha512=hashlib.sha512(payload.SerializeToString()).hexdigest()
        ).SerializeToString()

        signature = self._signer.sign(txn_header_bytes)
        return txn_header_bytes, signature

    def _batch_header(self, batch_key, transactions):
        batch_header_bytes = BatchHeader(
            signer_public_key=batch_key,
            transaction_ids=[txn.header_signature for txn in transactions],
        ).SerializeToString()

        signature = self._signer.sign(batch_header_bytes)

        return batch_header_bytes, signature
Beispiel #35
0
class HdfssbClient:
    def __init__(self, base_url, keyfile=None):

        self._base_url = base_url

        if keyfile is None:
            self._signer = None
            return

        try:
            with open(keyfile) as fd:
                private_key_str = fd.read().strip()
        except OSError as err:
            raise XoException(
                'Failed to read private key {}: {}'.format(
                    keyfile, str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as e:
            raise XoException(
                'Unable to load private key: {}'.format(str(e)))

        self._signer = CryptoFactory(create_context('secp256k1')) \
            .new_signer(private_key)

        self._publicKey = self._signer.get_public_key().as_hex()

        self._address_file = _hash(FAMILY_NAME.encode('utf-8'))[0:6] + \
                        _hash(self._publicKey.encode('utf-8'))[0:64]

    def get_public_key(self):
        return self._publicKey

    def _get_prefix(self):
        return _sha512('hdfssb'.encode('utf-8'))[0:6]

    def _get_prefix_file(self):
        return _sha512('file'.encode('utf-8'))[0:4]

    def _get_prefix_node(self):
        return _sha512('node'.encode('utf-8'))[0:4]

    def _get_address_file(self, name):
        hdfssb_prefix = self._get_prefix()
        file_prefix = self._get_prefix_file()
        name_hash = _sha512(name.encode('utf-8'))[0:60]
        return hdfssb_prefix + file_prefix + name_hash

    def _get_address_node(self, name):
        hdfssb_prefix = self._get_prefix()
        node_prefix = self._get_prefix_node()
        name_hash = _sha512(name.encode('utf-8'))[0:60]
        return hdfssb_prefix + node_prefix + name_hash

    def add_file(self, name, payload_object, wait=None, auth_user=None, auth_password=None):
        return self._send_xo_txn(
            name=name,
            address=self._get_address_file(name),
            payload_object=payload_object,
            action="add_file",
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def delete_file(self, name, wait=None, auth_user=None, auth_password=None):
        return self._send_xo_txn(
            name,
            None,
            "delete_file",
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def add_node(self, name, payload_object, wait=None, auth_user=None, auth_password=None):
        return self._send_xo_txn(
            name=name,
            address=self._get_address_node(name),
            payload_object=payload_object,
            action="add_node",
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def delete_node(self, name, wait=None, auth_user=None, auth_password=None):
        return self._send_xo_txn(
            name,
            None,
            "delete_node",
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def update_node(self, name, taken_space, wait=None, auth_user=None, auth_password=None):
        return self._send_xo_txn(
            name=name,
            payload_object={'taken_space': taken_space},
            action="update_node",
            wait=wait,
            auth_user=auth_user,
            auth_password=auth_password)

    def list_files(self, auth_user=None, auth_password=None):
        hdfssb_prefix = self._get_prefix()
        file_prefix = self._get_prefix_file()

        result = self._send_request(
            "state?address={}".format(hdfssb_prefix + file_prefix),
            auth_user=auth_user,
            auth_password=auth_password)

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            return [
                base64.b64decode(entry["data"]) for entry in encoded_entries
            ]

        except BaseException:
            return None

    def list_files_decoded(self):
        list_files = self.list_files()

        files = {}
        try:
            for node in list_files:
                file_name, owner, state, state, size, file_hash, blocks_str, checksums, data_bytes, oti_common, oti_scheme, last_update = node.decode().split(",")
                blocks = blocks_str.split("+")
                blocks_of_file = {}
                for pair in blocks:
                    block, node = pair.split(":")
                    blocks_of_file[block] = node

                files[file_name] = [file_name, owner, state, size, file_hash, blocks_of_file, checksums, data_bytes, oti_common, oti_scheme, last_update]
        except ValueError:
            raise InternalError("Failed to deserialize game data")

        return files

    def list_nodes(self, auth_user=None, auth_password=None):
        hdfssb_prefix = self._get_prefix()
        node_prefix = self._get_prefix_node()

        result = self._send_request(
            "state?address={}".format(hdfssb_prefix + node_prefix),
            auth_user=auth_user,
            auth_password=auth_password)

        try:
            encoded_entries = yaml.safe_load(result)["data"]

            return [
                base64.b64decode(entry["data"]) for entry in encoded_entries
            ]

        except BaseException:
            return None

    def list_nodes_decoded(self, auth_user=None, auth_password=None):
        list_nodes = self.list_nodes(auth_user, auth_password)

        nodes = {}
        try:
            for node in list_nodes:
                node_name, cluster, capacity, taken_space, reversed_space, last_update = node.decode().split(
                    ",")

                nodes[node_name] = {'node_name': node_name, 'cluster': cluster, 'capacity': capacity,
                                    'taken_space': taken_space, 'reversed_space': reversed_space,
                                    'last_update': last_update}
        except ValueError:
            raise InternalError("Failed to deserialize game data")

        return nodes

    def show_file(self, name, auth_user=None, auth_password=None):
        address = self._get_address_file(name)

        result = self._send_request(
            "state/{}".format(address),
            name=name,
            auth_user=auth_user,
            auth_password=auth_password)
        try:
            file = base64.b64decode(yaml.safe_load(result)["data"])

            file_name, owner, state, state, size, file_hash, blocks_str, checksums, data_bytes, oti_common, oti_scheme, last_update = file.decode().split(",")
            blocks = blocks_str.split("+")
            blocks_of_file = {}
            for pair in blocks:
                block, node = pair.split(":")
                blocks_of_file[block] = node

            file_json = {"file_name": file_name, 'owner': owner, 'state': state, 'size': size, 'file_hash': file_hash,
                         'blocks_of_file': blocks_of_file, 'checksums': checksums, 'data_bytes': data_bytes,
                         'oti_common': oti_common, 'oti_scheme': oti_scheme, 'last_update': last_update}

            #head = {'checksums': {"sha256": checksums}, 'data_bytes': int(data_bytes), 'oti_common': int(oti_common), 'oti_scheme': int(oti_scheme)}

            return file_json

        except BaseException:
            return None
        except ValueError:
            raise InternalError("Failed to deserialize game data")

    def _send_request(self,
                      suffix,
                      data=None,
                      content_type=None,
                      name=None,
                      auth_user=None,
                      auth_password=None):
        if self._base_url.startswith("http://"):
            url = "{}/{}".format(self._base_url, suffix)
        else:
            url = "http://{}/{}".format(self._base_url, suffix)

        headers = {}
        if auth_user is not None:
            auth_string = "{}:{}".format(auth_user, auth_password)
            b64_string = b64encode(auth_string.encode()).decode()
            auth_header = 'Basic {}'.format(b64_string)
            headers['Authorization'] = auth_header

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise XoException("No such game: {}".format(name))

            if not result.ok:
                raise XoException("Error {}: {}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise XoException(
                'Failed to connect to {}: {}'.format(url, str(err)))

        except BaseException as err:
            raise XoException(err)

        return result.text

    def _send_xo_txn(self,
                     name,
                     address,
                     payload_object,
                     action,
                     wait=None,
                     auth_user=None,
                     auth_password=None):

        if payload_object is None:
            payload_object = name

        json_payload = json.dumps({'action': action, 'payload': payload_object})
        payload = json_payload.encode()

        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="hdfssb",
            family_version="1.0",
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2 ** 64))
        ).SerializeToString()

        signature = self._signer.sign(header)

        transaction = Transaction(
            header=header,
            payload=payload,
            header_signature=signature
        )

        batch_list = self._create_batch_list([transaction])
        batch_id = batch_list.batches[0].header_signature

        if wait and wait > 0:
            wait_time = 0
            start_time = time.time()
            response = self._send_request(
                "batches", batch_list.SerializeToString(),
                'application/octet-stream',
                auth_user=auth_user,
                auth_password=auth_password)
            while wait_time < wait:
                status = self._get_status(
                    batch_id,
                    wait - int(wait_time),
                    auth_user=auth_user,
                    auth_password=auth_password)
                wait_time = time.time() - start_time

                if status != 'PENDING':
                    return response

            return response

        return self._send_request(
            "batches", batch_list.SerializeToString(),
            'application/octet-stream',
            auth_user=auth_user,
            auth_password=auth_password)

    def _create_batch_list(self, transactions):
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures
        ).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(
            header=header,
            transactions=transactions,
            header_signature=signature)
        return BatchList(batches=[batch])

    def wait_for_transaction(self, link):
        link = json.loads(link)["link"]
        status = "PENDING"
        limit = 30
        numer_attamps = 0
        while status == "PENDING" and numer_attamps < limit:
            result = requests.get(link)
            text_result = json.loads(result.text)
            status = text_result["data"][0]["status"]
            print(status)
            numer_attamps += 1
            time.sleep(1)
Beispiel #36
0
class SuseClient:
    """
    construct and send health transaction.
    """
    def __init__(self, base_url, work_path, keyfile=None):
        self._base_url = base_url
        self._work_path = work_path

        if keyfile is None:
            self._signer = None
            return

        try:
            with open(keyfile) as file_ptr:
                private_key_str = file_ptr.read().strip()
        except OSError as err:
            raise SuseException('Failed to read private key {}: {}'.format(
                keyfile, str(err)))

        try:
            private_key = Secp256k1PrivateKey.from_hex(private_key_str)
        except ParseError as parser_error:
            raise SuseException('Unable to load private key: {}'.format(
                str(parser_error)))

        self._signer = CryptoFactory(
            create_context('secp256k1')).new_signer(private_key)

    def suse(self, new_health, github_id):
        """
        Send commit url to code analysis

        Args:
            commit_url (str), git url to do a pull
            github_id (str), user github ID
        """

        txn_date = _get_date()

        #get latest health
        result = self._send_request("transactions")
        transactions = {}
        try:
            encoded_entries = yaml.safe_load(result)["data"]
            for entry in encoded_entries:
                #try to pull the specific transaction, if the format is not right
                #the transaction corresponds to the consesus family
                try:
                    transaction_type = base64.b64decode(
                        entry["payload"]).decode().split(',')[0]
                    if transaction_type == "health":
                        transactions[
                            entry["header_signature"]] = base64.b64decode(
                                entry["payload"])
                        #assuming we got all transactions in order
                        break
                except:
                    pass
            #return transactions
        except BaseException:
            return None

        for entry in transactions:
            previous_heatlh = transactions[entry].decode().split(',')[2]
            break

        suse = float(new_health) - float(previous_heatlh)

        #the amount of suse is related to the amount of health, with a realtion of 1-to-1
        #we also provide negative suses

        response = self._send_suse_txn(txn_type='suse',
                                       txn_id=github_id,
                                       data=str(suse),
                                       state='new',
                                       txn_date=txn_date)

        return response

    def list(self, txn_type=None, limit=None):
        """
        list all transactions.
        Args:
            txn_type (str), transaction type
            limit (int), number of transactions to pull
        """
        #pull all transactions of health family
        if limit is None:
            result = self._send_request("transactions")
        else:
            result = self._send_request("transactions?limit={}".format(limit))
        transactions = {}
        try:
            encoded_entries = yaml.safe_load(result)["data"]
            if txn_type is None:
                for entry in encoded_entries:
                    transactions[entry["header_signature"]] = base64.b64decode(
                        entry["payload"])

            else:
                for entry in encoded_entries:
                    #try to pull the specific transaction, if the format is not right
                    #the transaction corresponds to the consesus family
                    try:
                        transaction_type = base64.b64decode(
                            entry["payload"]).decode().split(',')[0]
                        if transaction_type == txn_type:
                            transactions[
                                entry["header_signature"]] = base64.b64decode(
                                    entry["payload"])
                    except:
                        pass
            return transactions
        except BaseException:
            return None

    def _get_prefix(self):
        """
        get suse family address prefix
        """
        return _sha512('suse'.encode('utf-8'))[0:6]

    def _get_address(self, txn_id):
        """
        get transaction address

        Args:
            id (str): trasaction id
        """
        suse_prefix = self._get_prefix()
        suse_address = _sha512(txn_id.encode('utf-8'))[0:64]
        return suse_prefix + suse_address

    def _send_request(self,
                      suffix,
                      data=None,
                      content_type=None,
                      auth_user=None,
                      auth_password=None):
        """
        send request to code smell processor`
        """
        if self._base_url.startswith("http://"):
            url = "{}/{}".format(self._base_url, suffix)
        else:
            url = "http://{}/{}".format(self._base_url, suffix)

        headers = {}
        if auth_user is not None:
            auth_string = "{}:{}".format(auth_user, auth_password)
            b64_string = b64encode(auth_string.encode()).decode()
            auth_header = 'Basic {}'.format(b64_string)
            headers['authorization'] = auth_header

        if content_type is not None:
            headers['Content-Type'] = content_type

        try:
            if data is not None:
                result = requests.post(url, headers=headers, data=data)
            else:
                result = requests.get(url, headers=headers)

            if result.status_code == 404:
                raise SuseException("No such transaction")
            elif not result.ok:
                raise SuseException("Error {}:{}".format(
                    result.status_code, result.reason))

        except requests.ConnectionError as err:
            raise SuseException('Failed to connect to {}:{}'.format(
                url, str(err)))

        except BaseException as err:
            raise SuseException(err)

        return result.text

    def _send_suse_txn(self,
                       txn_type=None,
                       txn_id=None,
                       data=None,
                       state=None,
                       txn_date=None):
        """
        serialize payload and create header transaction

        Args:
            type (str):    type of transaction
            id (str):      asset id, will depend on type of transaction
            data (object): transaction data
            state (str):   all transactions must have a state
        """
        #serialization is just a delimited utf-8 encoded strings
        payload = ",".join([txn_type, txn_id, data, state,
                            str(txn_date)]).encode()

        #pprint("payload: {}".format(payload))

        #construct the address
        address = self._get_address(txn_id)

        #construct header
        header = TransactionHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            family_name="suse",
            family_version="0.1",
            inputs=[address],
            outputs=[address],
            dependencies=[],
            payload_sha512=_sha512(payload),
            batcher_public_key=self._signer.get_public_key().as_hex(),
            nonce=hex(random.randint(0, 2**64))).SerializeToString()

        signature = self._signer.sign(header)

        #create transaction
        transaction = Transaction(header=header,
                                  payload=payload,
                                  header_signature=signature)

        #create batch list, suserum policy: one transaction per batch
        batch_list = self._create_batch_list([transaction])

        return self._send_request("batches", batch_list.SerializeToString(),
                                  'application/octet-stream')

    def _create_batch_list(self, transactions):
        """
        Create the list of batches that the client will send to the REST API

        Args:
            transactions (transaction): transaction(s) included in the batch

        Returns:
            BatchList: a list of batches to send to the REST API
        """
        transaction_signatures = [t.header_signature for t in transactions]

        header = BatchHeader(
            signer_public_key=self._signer.get_public_key().as_hex(),
            transaction_ids=transaction_signatures).SerializeToString()

        signature = self._signer.sign(header)

        batch = Batch(header=header,
                      transactions=transactions,
                      header_signature=signature)

        return BatchList(batches=[batch])