diff --git a/.gitignore b/.gitignore index 631e44495ad7478b58b994d2f8b5c1a278656c34..391626d7deaeade753f2b017a70e7da024835412 100644 --- a/.gitignore +++ b/.gitignore @@ -160,4 +160,8 @@ db.sqlite3 .idea TsaApi/*.pyc *.pyc -venv* \ No newline at end of file +venv* + +# pycache +app/__pycache__/* +TsaApi/__pycache__/* \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 50438ad815a0560502618fd6dc30adeb9ebaa018..7b49a021dc948be39e2146174b2b306ddaf1b84f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,13 @@ -FROM python:3.5 -RUN apt-get update && apt-get install -y --no-install-recommends apt-utils -RUN apt-get update && apt-get -y upgrade && apt-get install -y apt-transport-https software-properties-common libsasl2-dev python-dev libldap2-dev libssl-dev memcached +FROM python:3.5.2 +RUN apt-get update && apt-get -y upgrade && apt-get install -y --no-install-recommends apt-utils && apt-get install -y apt-transport-https software-properties-common libsasl2-dev python-dev libldap2-dev libssl-dev memcached RUN apt-get install -y gettext RUN git clone https://github.com/ethereum/pyethereum/ /opt/pyethereum -WORKDIR /opt/pyethereum -RUN python setup.py install -RUN mkdir -p /opt/project WORKDIR /opt/project ADD requirements.txt /opt/project RUN pip install -U pip RUN pip install -r requirements.txt +WORKDIR /opt/pyethereum +RUN python setup.py install +RUN mkdir -p /opt/project +WORKDIR /opt/project ADD . /opt/project \ No newline at end of file diff --git a/TsaApi/__init__.pyc b/TsaApi/__init__.pyc deleted file mode 100644 index 709a90ef202746dd2664b041994144486056b90b..0000000000000000000000000000000000000000 Binary files a/TsaApi/__init__.pyc and /dev/null differ diff --git a/TsaApi/__pycache__/__init__.cpython-35.pyc b/TsaApi/__pycache__/__init__.cpython-35.pyc deleted file mode 100644 index 0867da956487e6a335bfb989fe0874b2d9f426d3..0000000000000000000000000000000000000000 Binary files a/TsaApi/__pycache__/__init__.cpython-35.pyc and /dev/null differ diff --git a/TsaApi/__pycache__/local_settings.cpython-35.pyc b/TsaApi/__pycache__/local_settings.cpython-35.pyc deleted file mode 100644 index 28354c72868e8eb0125421bd92f3bf444edce855..0000000000000000000000000000000000000000 Binary files a/TsaApi/__pycache__/local_settings.cpython-35.pyc and /dev/null differ diff --git a/TsaApi/__pycache__/settings.cpython-35.pyc b/TsaApi/__pycache__/settings.cpython-35.pyc deleted file mode 100644 index 668ba9be9382f726c5b2730593daa0d9612b45a3..0000000000000000000000000000000000000000 Binary files a/TsaApi/__pycache__/settings.cpython-35.pyc and /dev/null differ diff --git a/TsaApi/__pycache__/urls.cpython-35.pyc b/TsaApi/__pycache__/urls.cpython-35.pyc deleted file mode 100644 index 6ce68b54ef09b2ae4314920357e91db955db5c29..0000000000000000000000000000000000000000 Binary files a/TsaApi/__pycache__/urls.cpython-35.pyc and /dev/null differ diff --git a/TsaApi/__pycache__/wsgi.cpython-35.pyc b/TsaApi/__pycache__/wsgi.cpython-35.pyc deleted file mode 100644 index 2188d4539e91a971edc54ec9a54a32df922a194f..0000000000000000000000000000000000000000 Binary files a/TsaApi/__pycache__/wsgi.cpython-35.pyc and /dev/null differ diff --git a/TsaApi/local_settings.pyc b/TsaApi/local_settings.pyc deleted file mode 100644 index ea0a8c6f2daef69f37741515fb3ea8bd9383e1a4..0000000000000000000000000000000000000000 Binary files a/TsaApi/local_settings.pyc and /dev/null differ diff --git a/TsaApi/settings.py b/TsaApi/settings.py index b34187e28c258d435ab866e27007c0dda91bf5b5..1ad48e3fa4f20e614c78ac9f80a4808d854f79ca 100644 --- a/TsaApi/settings.py +++ b/TsaApi/settings.py @@ -237,7 +237,7 @@ LOGGING = { }, 'logger': { 'handlers': ['error_file', 'info_file', 'sentry'], - 'level': 'ERROR', + 'level': 'INFO', 'propagate': True, }, 'console-logger': { diff --git a/TsaApi/settings.pyc b/TsaApi/settings.pyc deleted file mode 100644 index a3a5461550eef7903024869749a1e45c2914eb17..0000000000000000000000000000000000000000 Binary files a/TsaApi/settings.pyc and /dev/null differ diff --git a/app/__pycache__/__init__.cpython-35.pyc b/app/__pycache__/__init__.cpython-35.pyc deleted file mode 100644 index 24d1a5b248593470699ea6ca599e2ad3ab41f35e..0000000000000000000000000000000000000000 Binary files a/app/__pycache__/__init__.cpython-35.pyc and /dev/null differ diff --git a/app/__pycache__/managers.cpython-35.pyc b/app/__pycache__/managers.cpython-35.pyc deleted file mode 100644 index 84414991941a0fd259b67fa171434bb6480e741d..0000000000000000000000000000000000000000 Binary files a/app/__pycache__/managers.cpython-35.pyc and /dev/null differ diff --git a/app/__pycache__/tests.cpython-35.pyc b/app/__pycache__/tests.cpython-35.pyc deleted file mode 100644 index 141c512ef8dc016ba00a152829e2128983e736d9..0000000000000000000000000000000000000000 Binary files a/app/__pycache__/tests.cpython-35.pyc and /dev/null differ diff --git a/app/__pycache__/urls.cpython-35.pyc b/app/__pycache__/urls.cpython-35.pyc deleted file mode 100644 index 602e748e6acf4f15fbeb391bb9b5166a1e478622..0000000000000000000000000000000000000000 Binary files a/app/__pycache__/urls.cpython-35.pyc and /dev/null differ diff --git a/app/__pycache__/utils.cpython-35.pyc b/app/__pycache__/utils.cpython-35.pyc deleted file mode 100644 index 767ebaa7167744a271dfa368637b20ddaf7d18de..0000000000000000000000000000000000000000 Binary files a/app/__pycache__/utils.cpython-35.pyc and /dev/null differ diff --git a/app/__pycache__/views.cpython-35.pyc b/app/__pycache__/views.cpython-35.pyc deleted file mode 100644 index 23d4e3818c6a522e24813642e31c0aa94e39d530..0000000000000000000000000000000000000000 Binary files a/app/__pycache__/views.cpython-35.pyc and /dev/null differ diff --git a/app/managers.py b/app/managers.py index ffe482e7b968701abcc6fdf708016e3058f2dbcc..11f17ef8b030c32ad842fbe00fe6f91dc74074bd 100644 --- a/app/managers.py +++ b/app/managers.py @@ -64,11 +64,11 @@ class TimestampManager(models.Manager): def stamp(proof_hash, file_hash): contract = TimestampManager.get_current_contract() - - web3 = TimestampManager.get_provider() - return contract.functions.stamp(proof_hash, file_hash).transact({'from': Web3.toChecksumAddress(ACCOUNT_ADDRESS), 'gas': GAS, 'gasPrice': web3.eth.gasPrice}) + web3 = TimestampManager.get_provider() + return contract.functions.stamp(proof_hash, file_hash).transact( + {'from': Web3.toChecksumAddress(ACCOUNT_ADDRESS), 'gas': GAS, 'gasPrice': web3.eth.gasPrice}) @staticmethod def verify(contract_version, proof_hash, file_hash): @@ -105,7 +105,7 @@ class EthereumGateway: last_block_number = TimestampManager.get_last_block_number() tx_block_number = transaction.blockNumber required_block_difference = Utils.required_block_difference(TimestampManager.get_signers_count()) - return (last_block_number - tx_block_number) < required_block_difference + return (last_block_number - tx_block_number) > required_block_difference def transaction(self, tx_hash): return TimestampManager.get_transaction(tx_hash) @@ -125,7 +125,7 @@ class EthereumGateway: w3 = TimestampManager.get_provider() tx_2 = w3.eth.getTransaction(tx['hash']) if tx_2['blockNumber'] is not None: - raise TxAlreadySealedInBlock("Tx already seald in block {}".format(str(tx_2['blockNumber']))) + raise TxAlreadySealedInBlock("Tx already sealed in block {}".format(str(tx_2['blockNumber']))) return w3.eth.resend(tx, gas_price, gas) @@ -135,4 +135,7 @@ class TimeStamp: return CONTRACTS[CURRENT_CONTRACT_VERSION]['abi'] def verify(self, proof_hash, file_hash): - return TimestampManager.verify(CURRENT_CONTRACT_VERSION, proof_hash, file_hash) \ No newline at end of file + return TimestampManager.verify(CURRENT_CONTRACT_VERSION, proof_hash, file_hash) + + def get_block(self, proof_hash): + return TimestampManager.get_block_number(CURRENT_CONTRACT_VERSION, proof_hash) diff --git a/app/migrations/__pycache__/__init__.cpython-35.pyc b/app/migrations/__pycache__/__init__.cpython-35.pyc index 607aff09d96f8a1e3491a03b221cf63b89707c10..2387a6ec660cdb84289934a600da42e18277676c 100644 Binary files a/app/migrations/__pycache__/__init__.cpython-35.pyc and b/app/migrations/__pycache__/__init__.cpython-35.pyc differ diff --git a/app/services.py b/app/services.py index ef5c01ea48ca6e445e44d4984580bc671aa9f63f..ab51a9e37a7fee79c778f049321d9de6f2097e0b 100644 --- a/app/services.py +++ b/app/services.py @@ -9,6 +9,8 @@ import logging import json from sys import stdout +from django.utils.translation import gettext as _, gettext + if stdout.isatty(): log_str = 'console-logger' else: @@ -16,14 +18,6 @@ else: module_logger = logging.getLogger(log_str) -class DefinitiveReceiptGenerator: - encoder = Base64EncodingService() - - def generate_definitive_receipt(self, original_file_hash, ots_hash, tx_hash, block): - base64.b64encode( - Utils.get_permanent_ots(original_file_hash, ots_hash, tx_hash, - block.number).encode('utf-8')).decode('utf-8') - class ReceiptInterpreter: @@ -31,13 +25,24 @@ class ReceiptInterpreter: return ots.split('-') +class DefinitiveReceiptGenerator: + encoder = Base64EncodingService() + interpreter = ReceiptInterpreter() + gateway = EthereumGateway() + + def generate_definitive_receipt(self, original_file_hash, tx_hash, ots_hash): + tx = self.gateway.transaction(tx_hash) + return self.encoder.encode(Utils.get_permanent_ots(original_file_hash, ots_hash, tx_hash, + tx['blockNumber']).encode('utf-8')).decode('utf-8') + + class TransactionInputVerification: gateway = EthereumGateway() interpreter = ReceiptInterpreter() ts = TimeStamp() tx_hash = '' - def verify(self, ots): + def verify(self, original_file_hash, ots): ots_version, file_hash, ots_hash, tx_hash, block_number = self.interpreter.interpret(ots) method_name, args = Utils.decode_contract_call(self.ts.abi(), TimestampManager.get_transaction(tx_hash).input) return args[0].decode('utf-8') == ots_hash and args[1].decode('utf-8') == file_hash @@ -46,61 +51,93 @@ class TransactionInputVerification: class SmartContractVerification: timestamp = TimeStamp() interpreter = ReceiptInterpreter() + gateway = EthereumGateway() - def verify(self, ots): - ots_version, file_hash, ots_hash, tx_hash, block_number = self.interpreter.interpret(ots) - self.timestamp.verify(ots_hash, file_hash) + def verify(self, file_hash, ots_hash): + verified = self.timestamp.verify(ots_hash, file_hash) + block = None + if verified: + block_number = self.timestamp.get_block(ots_hash) + block = self.gateway.block(block_number) + return verified, block + + +class EventVerification: + gateway = EthereumGateway() class VerifyService: receipt_generator = DefinitiveReceiptGenerator() - definitive_verificator = TransactionInputVerification() + definitive_verificator = SmartContractVerification() + temp_verificator = SmartContractVerification() + interpreter = ReceiptInterpreter() gateway = EthereumGateway() permanent_ots_prefix = '' - def verify(self, original_file_hash, ots): - if ots[:2] == self.permanent_ots_prefix: - if self.definitive_verificator.verify(ots): - block = TimestampManager.get_block(int(block_number)) - return { - 'status': 'success', - 'messages': ('file_uploaded') % (str(original_file_hash), str(block.number), - str(Utils.datetime_from_timestamp(block.timestamp)))} + def verify(self, original_file_hash, rd): + if rd[:2] == self.permanent_ots_prefix: + ots_version, file_hash, ots_hash, tx_hash, block_number = self.interpreter.interpret(rd) + verified, block = self.definitive_verificator.verify(original_file_hash, ots_hash) + if verified: + return {'status': 'success', + 'block': block, + 'permanent_rd': self.receipt_generator.generate_definitive_receipt(original_file_hash, + tx_hash, + ots_hash)} else: - return {'status': 'failure', 'messages': 'file_not_found'} + return {'status': 'failure'} else: - - ots_version, ots_hash, tx_hash = ots.split('-') - transaction = TimestampManager.get_transaction(tx_hash) - contract_version = ots_hash[-2:] - - if TimestampManager.verify(contract_version, ots_hash, original_file_hash): - - if ( - TimestampManager.get_last_block_number() - transaction.blockNumber) < Utils.required_block_difference( - TimestampManager.get_signers_count()): - return {'status': 'pending', 'messages': 'transaction_pending'} + ots_version, ots_hash, tx_hash = self.interpreter.interpret(rd) + verified, block = self.temp_verificator.verify(original_file_hash, ots_hash) + tx = self.gateway.transaction(tx_hash) + if verified: + if not self.gateway.transaction_is_canonical(tx): + return {'status': 'pending'} else: - - block = TimestampManager.get_block( - TimestampManager.get_block_number(contract_version, ots_hash)) - return {'status': 'success', - 'permanent_rd': base64.b64encode( - Utils.get_permanent_ots(original_file_hash, ots_hash, tx_hash, - block.number).encode('utf-8')).decode('utf-8'), - 'messages': 'file_uploaded' % ( - original_file_hash, str(block.number), str( - Utils.datetime_from_timestamp(block.timestamp)))} + 'block': block, + 'permanent_rd': self.receipt_generator.generate_definitive_receipt(original_file_hash, + tx_hash, + ots_hash)} else: try: - if transaction and not transaction.blockNumber: - return {'status': 'pending', 'messages': 'transaction_pending'} + if tx and not tx.blockNumber: + return {'status': 'pending'} except ValueError: pass - return {'status': 'failure', 'messages': 'file_not_found'} + return {'status': 'failure'} + + +class StatusNotValidException(Exception): + pass + + +class VerifyServiceTranslation: + verify_service = VerifyService() + + def verify(self, original_file_hash, rd): + result = self.verify_service.verify(original_file_hash, rd) + dict_res = {gettext('status'): result['status']} + res_status = 200 + if result['status'] == 'success': + dict_res[gettext('permanent_rd')] = result['permanent_rd'] + dict_res[gettext('attestation_time')] = str(Utils.datetime_from_timestamp(result['block'].timestamp)) + dict_res[gettext('messages')] = gettext('file_uploaded') % ( + original_file_hash, + str(result['block'].number), + str(Utils.datetime_from_timestamp(result['block'].timestamp)) + ) + elif result['status'] == 'failure': + dict_res[gettext('messages')] = gettext('file_not_found') + res_status = 404 + elif result['status'] == 'pending': + dict_res[gettext('messages')] = gettext('transaction_pending') + else: + raise StatusNotValidException('Status invalid in verify service result : {}'.format(result['status'])) + + return dict_res, res_status class MemcachedStorage: diff --git a/app/tests.py b/app/tests.py index 0e7b9b345fe260c3f65baad790d4e8979132d8f9..08b37f0e66a755ebfbe319bbb9a1dc33aa0727f5 100644 --- a/app/tests.py +++ b/app/tests.py @@ -7,37 +7,47 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/ """ +import base64 +import json +import time +import unittest + +from django.utils.translation import gettext as _ from django.test import TestCase from django.test import Client from eth_account.datastructures import AttributeDict from pymemcache.client import base from rest_framework import status -from TsaApi.settings import TEST_MEMCACHED_HOST, TEST_MEMCACHED_PORT, TEST_PENDING_TXS_MEMCACHED_KEY - -from app.services import PendingTransactionsService, CheckCriteria, MemcachedStorage, TransactionUnstucker +from TsaApi.settings import TEST_MEMCACHED_HOST, TEST_MEMCACHED_PORT, TEST_PENDING_TXS_MEMCACHED_KEY, \ + PERMANENT_OTS_PREFIX +from app.services import PendingTransactionsService, CheckCriteria, MemcachedStorage, TransactionUnstucker, \ + VerifyService -class TimestampTest(TestCase): - - def test_verify(self): - c = Client() - response = c.post('/api/tsa/verify/', { - "file_hash": "1957db7fe23e4be1740ddeb941ddda7ae0a6b782e536a9e00b5aa82db1e84547", - "proof": "NjA2MWQ1ODNkMTM0YTlmZGZlYWYxMWE2MjY1ZDY1OTkwMGM0ZGZjNjM2MDk3MDY4N2VkNDk3NTNhZmE5MGM3YzAxLTB4NWRiYjg4NjNlNDlhN2NmYTY0N2FmYzVkOTFkMWRiMDUxY2YzODZiYWY4NzJkM2ZiYTIzN2JkY2IwOWUwNWMzYQ==" - }) - self.assertEqual(response.status_code, status.HTTP_200_OK, 'Verify Error') +class TimestampTest(unittest.TestCase): - def test_stamp(self): + def test_full_cycle(self): c = Client() response = c.post('/api/tsa/stamp/', { "file_hash": "1957db7fe23e4be1740ddeb941ddda7ae0a6b782e536a9e00b5aa82db1e84547" }) self.assertEqual(response.status_code, status.HTTP_200_OK, 'Stamp Error') + dict_response = json.loads(response.content.decode()) + time.sleep(30) + verify_response = c.post('/api/tsa/verify/', { + "file_hash": "1957db7fe23e4be1740ddeb941ddda7ae0a6b782e536a9e00b5aa82db1e84547", + "rd": dict_response['temporary_rd'] + }) -class EthereumMocks(): + self.assertEqual(verify_response.status_code, status.HTTP_200_OK, 'Verify Error') + dict_verify = json.loads(verify_response.content.decode()) + self.assertEqual(dict_verify[_('status')], _('success')) + + +class EthereumMocks: class HalfResender: balance = 2.1 * 21000 * 1000 # me da para 2 txs mockeadas @@ -211,7 +221,7 @@ class EthereumMocks(): ] -class PendingTransactionTest(TestCase, EthereumMocks): +class PendingTransactionTest(unittest.TestCase, EthereumMocks): def setUp(self): self.service = PendingTransactionsService() @@ -264,7 +274,7 @@ class PendingTransactionTest(TestCase, EthereumMocks): self.assertEqual(failed, [txs[-1]]) -class MemcachedStorageTest(TestCase): +class MemcachedStorageTest(unittest.TestCase): def setUp(self): self.storage = MemcachedStorage() @@ -306,7 +316,7 @@ class MemcachedStorageTest(TestCase): self.assertEqual(some_stuff, retrieved) -class TransactionUnstuckerTest(TestCase, EthereumMocks): +class TransactionUnstuckerTest(unittest.TestCase, EthereumMocks): def setUp(self): self.unstucker = TransactionUnstucker() @@ -360,3 +370,90 @@ class TransactionUnstuckerTest(TestCase, EthereumMocks): res, failed = self.unstucker.unstuck_pending_transactions(1000) self.assertEqual(failed, []) self.assertEqual(res, []) # como no tenÃa cache entonces no se hizo nada + + +class VerificationMocks: + class NotSealedTransactionMock: + def transaction(self, tx_hash): + return AttributeDict( + {'hash': tx_hash, 'blockNumber': None}) + + class SealedTransactionMock: + def transaction(self, tx_hash): + return AttributeDict( + {'hash': tx_hash, 'blockNumber': 1000}) + + class TXisCanonicalMock: + def transaction_is_canonical(self, tx): + return True + + class TXisNotCanonicalMock: + def transaction_is_canonical(self, tx): + return False + + class FalseVerificationMock: + def verify(self, file_hash, ots_hash): + return False, None + + class TrueVerificationMock: + def verify(self, file_hash, ots_hash): + return True, AttributeDict({'number': 1000}) + + class TxCanonicalSealedTx(SealedTransactionMock, TXisCanonicalMock): + pass + + class TxNoCanonicalSealedTx(SealedTransactionMock, TXisNotCanonicalMock): + pass + + class ReceiptGeneratorMock: + def generate_definitive_receipt(self, original_file_hash, tx_hash, ots_hash): + return "{}{}{}".format(original_file_hash, tx_hash, ots_hash) + + +class VerifyServiceTest(unittest.TestCase, VerificationMocks): + + def setUp(self): + self.service = VerifyService() + self.service.permanent_ots_prefix = PERMANENT_OTS_PREFIX + self.ots = "d6b88be854cb88cf1e161d8bbd912987cff236eb43a3a15fff86370054dd4d3f01" + self.file_hash = 'some_hash' + self.contract_version = '01' + self.temp_rd = "0x-d6b88be854cb88cf1e161d8bbd912987cff236eb43a3a15fff86370054dd4d3f01-0xf495705b5d7d68afdcefe72d9bbacec59b1a968c964ab0b6b13cec6491e5ddec" + self.def_rd = "1x-7b58a42ee27c3699fc169ce43cb4ba598003cba5699f4cd518b91d4177f61f10-0577d1390a5733534c7b6cc45a7ba15d0b5bf37faec9c54f749826af75aa86bb01-0x1a3a5335b44bdb7f62201102e91658586fd1d7845c621503eeff7781c3020b09-2234445" + pass + + def test_verify_temporary_rd_not_sealed(self): + self.service.gateway = self.NotSealedTransactionMock() + self.service.temp_verificator = self.FalseVerificationMock() + res = self.service.verify(self.file_hash, self.temp_rd) + self.assertEqual(res['status'], 'pending') + + def test_verify_temporary_rd_sealed_not_canonical(self): + self.service.gateway = self.TxNoCanonicalSealedTx() + self.service.temp_verificator = self.TrueVerificationMock() + res = self.service.verify(self.file_hash, self.temp_rd) + self.assertEqual(res['status'], 'pending') + + def test_verify_temporary_rd_sealed_canonical(self): + self.service.temp_verificator = self.TrueVerificationMock() + self.service.gateway = self.TxCanonicalSealedTx() + self.service.receipt_generator.gateway = self.SealedTransactionMock() + res = self.service.verify(self.file_hash, self.temp_rd) + + self.assertEqual(res['status'], 'success') + rd = res['permanent_rd'] + ots_version, file_hash, ots_hash, tx_hash, block_number = base64.b64decode(rd).decode().split('-') + self.assertEqual(ots_version, PERMANENT_OTS_PREFIX) + self.assertEqual(file_hash, self.file_hash) + self.assertEqual(ots_hash, self.ots) + self.assertEqual(res['block'].number, int(block_number)) + + def test_definitive_rd_correct(self): + self.service.definitive_verificator = self.TrueVerificationMock() + self.service.receipt_generator = self.ReceiptGeneratorMock() + res = self.service.verify(self.file_hash, self.def_rd) + self.assertEqual(res['status'], 'success') + + def test_definitive_rd_incorrect(self): + res = self.service.verify(self.file_hash, self.def_rd) + self.assertEqual(res['status'], 'failure') diff --git a/app/utils.py b/app/utils.py index bb5eab97de531106ec790465048595ef703439f5..d3fa00b4a3437e6d46acada06ef032f7893f04aa 100644 --- a/app/utils.py +++ b/app/utils.py @@ -13,8 +13,6 @@ import hashlib import time import math from TsaApi.settings import ACCOUNT_ADDRESS, CURRENT_CONTRACT_VERSION, PERMANENT_OTS_PREFIX, TEMPORARY_OTS_PREFIX -from ethereum.abi import (decode_abi, normalize_name as normalize_abi_method_name, method_id as get_abi_method_id) -from ethereum.utils import encode_int, zpad, decode_hex class Utils: diff --git a/app/views.py b/app/views.py index 22e03de2b1b1c35943b9199643b2d69ef24e8d58..2642b5be2446c92b319d7590066f9629c5c372ca 100644 --- a/app/views.py +++ b/app/views.py @@ -8,19 +8,25 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/ """ import base64 +import logging + +import coreapi +import coreschema from django.core.exceptions import ValidationError from django.utils.translation import gettext as _ +from raven.contrib.django.raven_compat.models import client from rest_framework import status -from rest_framework.views import APIView from rest_framework.response import Response -from web3.exceptions import CannotHandleRequest -from raven.contrib.django.raven_compat.models import client from rest_framework.schemas import ManualSchema -import coreschema, coreapi +from rest_framework.views import APIView +from web3.exceptions import CannotHandleRequest +from TsaApi.local_settings import PERMANENT_OTS_PREFIX from app.managers import TimestampManager +from app.services import VerifyServiceTranslation from app.utils import Utils -from TsaApi.local_settings import TEMPORARY_OTS_PREFIX, PERMANENT_OTS_PREFIX, CONTRACTS + +logger = logging.getLogger('logger') class Stamp(APIView): @@ -61,8 +67,9 @@ class Stamp(APIView): ots_hash = Utils.get_ots_hash(file_hash) + logger.info("Haciendo stamp para hash: {} ots: {} ".format(file_hash, ots_hash)) tx_hash = TimestampManager.stamp(ots_hash, file_hash) - + logger.info("Stamp para hash: {} ots: {} terminado, tx_hash : {}".format(file_hash, ots_hash, tx_hash.hex())) # Al OTS se le agrega la transacción para poder verificar luego si está pendiente de subida ots = Utils.get_temporary_ots(ots_hash, tx_hash.hex()) @@ -117,6 +124,8 @@ class Verify(APIView): ) ]) + verify_service = VerifyServiceTranslation() + def post(self, request): try: @@ -127,75 +136,26 @@ class Verify(APIView): raise ValidationError('rd') original_file_hash = request.data.get('file_hash') - base64_ots = request.data.get('rd') - - ots = base64.b64decode(base64_ots).decode('utf-8') - - if ots[:2] == PERMANENT_OTS_PREFIX: - - ots_version, file_hash, ots_hash, tx_hash, block_number = ots.split('-') - - method_name, args = Utils.decode_contract_call(CONTRACTS['01']['abi'], - TimestampManager.get_transaction(tx_hash).input) + base64_rd = request.data.get('rd') - if args[0].decode('utf-8') == ots_hash and args[1].decode('utf-8') == file_hash: - - block = TimestampManager.get_block(int(block_number)) - - return Response({_('status'): _('success'), - _('permanent_rd'): base64.b64encode(Utils.get_permanent_ots(original_file_hash, ots_hash, tx_hash, block.number).encode('utf-8')).decode('utf-8'), - _('attestation_time'): str(Utils.datetime_from_timestamp(block.timestamp)), - _('messages'): _('file_uploaded') % ( - file_hash, str(block.number), - str(Utils.datetime_from_timestamp(block.timestamp)))}, - status=status.HTTP_200_OK) - else: - return Response({_('status'): _('failure'), _('messages'): _('file_not_found')}, - status=status.HTTP_404_NOT_FOUND) - - else: - - ots_version, ots_hash, tx_hash = ots.split('-') - - transaction = TimestampManager.get_transaction(tx_hash) - - contract_version = ots_hash[-2:] - - if TimestampManager.verify(contract_version, ots_hash, original_file_hash): - - if ( - TimestampManager.get_last_block_number() - transaction.blockNumber) < Utils.required_block_difference( - TimestampManager.get_signers_count()): - return Response({_('status'): _('pending'), _('messages'): _('transaction_pending')}, - status=status.HTTP_200_OK) - else: - - block = TimestampManager.get_block( - TimestampManager.get_block_number(contract_version, ots_hash)) - - return Response({_('status'): _('success'), - _('permanent_rd'): base64.b64encode(Utils.get_permanent_ots(original_file_hash, ots_hash, tx_hash, block.number).encode('utf-8')).decode('utf-8'), - _('attestation_time'): str(Utils.datetime_from_timestamp(block.timestamp)), - _('messages'): _('file_uploaded') % (original_file_hash, str(block.number), str( - Utils.datetime_from_timestamp(block.timestamp)))}, status=status.HTTP_200_OK) - else: - try: - if transaction and not transaction.blockNumber: - return Response({_('status'): _('pending'), _('messages'): _('transaction_pending')}, - status=status.HTTP_200_OK) - except ValueError: - pass - - return Response({_('status'): _('failure'), _('messages'): _('file_not_found')}, - status=status.HTTP_404_NOT_FOUND) + rd = base64.b64decode(base64_rd).decode('utf-8') + # importante la asignación del prefijo de ots permanente + self.verify_service.verify_service.permanent_ots_prefix = PERMANENT_OTS_PREFIX + logger.info("Iniciando verificacion para hash {} rd {} baserd {}".format(original_file_hash, rd, base64_rd)) + result, res_status = self.verify_service.verify(original_file_hash, rd) + logger.info( + "Verificacion terminada para hash {} rd {}, resultado {}".format(original_file_hash, rd, str(result))) + return Response(result, status=res_status) except ValidationError as e: return Response({_('status'): _('failure'), _('messages'): _('parameter_missing') % e.message}, status=status.HTTP_400_BAD_REQUEST) - except CannotHandleRequest: + except CannotHandleRequest as e: + logger.critical('Servicio a nivel Geth no disponible!! error: {}'.format(str(e))) return Response({_('status'): _('failure'), _('messages'): _('could_not_connect')}, status=status.HTTP_503_SERVICE_UNAVAILABLE) except Exception as e: client.captureException() + logger.error('Error interno en la verificacion : {}'.format(str(e))) return Response({_('status'): _('failure'), _('messages'): _('operation_failed')}, - status=status.HTTP_500_INTERNAL_SERVER_ERROR) \ No newline at end of file + status=status.HTTP_500_INTERNAL_SERVER_ERROR) diff --git a/pyethereum b/pyethereum deleted file mode 160000 index d962694be03686a8e5c1d7459ae272b70a5c9f77..0000000000000000000000000000000000000000 --- a/pyethereum +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d962694be03686a8e5c1d7459ae272b70a5c9f77 diff --git a/requirements.txt b/requirements.txt index aaa7cba7627db42049d00ca5648b355df214497b..e7e919e6c5f1ea1ae27a23d4c7d124c58f98abfe 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,14 +1,13 @@ -asn1crypto==0.24.0 +ipython==7.2.0 +ipython-genutils==0.2.0 +pymemcache==2.1.1 +elastic-apm==3.0.0 attrdict==2.0.0 -backcall==0.1.0 certifi==2018.4.16 -cffi==1.12.0 chardet==3.0.4 -coincurve==11.0.0 coreapi==2.3.3 coreschema==0.0.4 cytoolz==0.9.0.1 -decorator==4.3.2 Django==2.1 django-cors-headers==2.4.0 django-rest-swagger==2.2.0 @@ -20,50 +19,26 @@ eth-hash==0.1.4 eth-keyfile==0.5.1 eth-keys==0.2.0b3 eth-rlp==0.1.2 -eth-typing==2.0.0 eth-utils==1.0.3 -ethereum==2.3.2 -future==0.17.1 hexbytes==0.1.0 idna==2.7 -ipython==7.2.0 -ipython-genutils==0.2.0 itypes==1.1.0 -jedi==0.13.2 Jinja2==2.10 lru-dict==1.1.6 MarkupSafe==1.0 openapi-codec==1.3.2 parsimonious==0.8.0 -parso==0.3.4 -pbkdf2==1.3 -pexpect==4.6.0 -pickleshare==0.7.5 -prompt-toolkit==2.0.8 -ptyprocess==0.6.0 -py-ecc==1.4.7 -pycparser==2.19 pycryptodome==3.6.4 -pyethash==0.1.27 -Pygments==2.3.1 PyJWT==1.6.4 -pymemcache==2.1.1 -pysha3==1.0.2 python-bitcoinlib==0.10.1 pytz==2018.5 -PyYAML==4.2b4 raven==6.9.0 -repoze.lru==0.7 requests==2.19.1 rlp==1.0.1 -scrypt==0.8.13 simplejson==3.16.0 six==1.11.0 toolz==0.9.0 -traitlets==4.3.2 uritemplate==3.0.0 urllib3==1.23 -wcwidth==0.1.7 web3==4.5.0 -websockets==5.0.1 -elastic-apm==3.0.0 \ No newline at end of file +websockets==5.0.1 \ No newline at end of file