Skip to content

Commit 915e69c

Browse files
Merge branch 'develop' into feature/fix_hashcash_difficulty
* develop: (39 commits) Add full 151 name in main title Small changes to design in landing (margin of title) Add nom 151 subtitle and info on base.html Update simple copy Update copies and links in tx validation Cleanup tx detail Update definitions and copy in tx detail Update definitions on block definition, translate and clean up Update copy on block detail view Update copy and some links update merkleroot reference on template update tx reference update validate transaction view some ui changes(link, ccs) send raw validate data to validation certificate view save conservation certificate on their own table add block to conservation model and make reference unique add view, template and url to validate certificate add validate request and return parsed result fix flake8 warnings ...
2 parents ce064d0 + 6c8a824 commit 915e69c

File tree

25 files changed

+497
-121
lines changed

25 files changed

+497
-121
lines changed

CONTRIBUTING.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,18 @@ git remote add Prescrypto https://github.com/Prescrypto/RexChain
5151
git fetch prescrypto
5252

5353
__Create a vagrant machine:__
54-
__#inside the directory run the vagrantfile__
54+
__# inside the directory run the vagrantfile__
5555
$ vagrant up
56-
__#get server running and start creating stuff__
56+
__# get server running and start creating stuff__
5757
$ vagrant ssh
5858

5959
$ cd /vagrant/rexchain
6060
$ python3.6 manage.py migrate
6161
$ python3.6 manage.py loaddata ./fixtures/initial_data.json
6262
$ python3.6 manage.py runserver [::]:8000
6363

64-
__#Wake Up Redis Worker__
65-
__#Open a new window console enter to ssh of vagrant and run these commands__
64+
__# Wake Up Redis Worker__
65+
__# Open a new window console enter to ssh of vagrant and run these commands__
6666
$ cd /vagrant/rexchain
6767
$ python3.6 manage.py rqworker high default low
6868

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
# RexChain - a Python - SQL based lightweight, cryptographically enabled, centralised blockchain implementation – Originally forked from NaiveChain and ported into Python, but no original code remains.
2+
# RexChain - a Python - SQL based lightweight, cryptographically enabled, centralised blockchain implementation.
33

44
[![Build Status](https://travis-ci.org/Prescrypto/RexChain.svg?branch=master)](https://travis-ci.org/Prescrypto/RexChain)
55

@@ -8,7 +8,7 @@
88

99

1010
### Motivation
11-
All the current implementations of blockchains are tightly coupled with the larger context and problems they (e.g. Bitcoin or Ethereum) are trying to solve. This leaves little room to implement different solutions. Especially source-code-wisely. This project is an attempt to provide a lightweight concise and simple implementation of a blockchain as possible, completely designed around electronic medical prescriptions.
11+
All the current implementations of blockchains are tightly coupled with the larger context and problems they (e.g. Bitcoin or Ethereum) are trying to solve. This leaves room to implement domain specific solutions. Especially source-code-wisely. This project is an attempt to provide a lightweight concise and simple implementation of a blockchain as possible, completely designed around electronic medical prescriptions and structured medical data.
1212

1313

1414
### What is blockchain
@@ -21,9 +21,9 @@ All the current implementations of blockchains are tightly coupled with the larg
2121
* At the moment it is a centralised chain of blocks, the block's merkle root can be anchored with Proof of Existence to any particular distributed Blockchain (in a similar way to Factom's white paper) (https://github.com/FactomProject/FactomDocs/blob/master/whitepaper.md)
2222
* At the moment data is persisted in an SQL implementation
2323
* Access to the database is enabled by Asymetric Cryptography
24-
* Proof-of-work thourght Hashcash (http://www.hashcash.org/hashcash.pdf) for to stop fake data from being created.
24+
* Proof-of-work thourght Hashcash (http://www.hashcash.org/hashcash.pdf)
2525
* Transactions: You can transfer data through [Prescrypto Wallet](https://prescrypto.github.io/wallet/deploy/feature_rexchain_wallet/) [See more over __Transactions__ concept in our [wiki](https://github.com/Prescrypto/RexChain/wiki/Transacciones)].
26-
* Distributed version: This is step follow.
26+
* Distributed version: This step will follow.
2727

2828
### Quick start
2929
(set up node and mine 1 block)
@@ -99,7 +99,7 @@ The test ends successfully when the console shows:
9999

100100
`OK`
101101

102-
__Remark__
102+
__Note__
103103

104104
The console can ask the following:
105105

@@ -126,4 +126,4 @@ You must run the following commands in order to add the coverage badge:
126126
$ coverage-badge -o coverage.svg
127127
```
128128

129-
Note: Run coverage command and coverage report is required!
129+
Note: Run coverage command and coverage report!

app.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,15 @@
7171
},
7272
"JIRA_PASSWORD": {
7373
"required": true
74+
},
75+
"REACHCORE_ENTITY": {
76+
"required": true
77+
},
78+
"REACHCORE_USER": {
79+
"required": true
80+
},
81+
"REACHCORE_PASS": {
82+
"required": true
7483
}
7584
},
7685
"formation": {

requirements.txt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# django
2-
Django==1.11.11
2+
Django==1.11.29
33

44
# Heroku
55
gunicorn==19.7.1
@@ -10,20 +10,21 @@ psycopg2-binary==2.7.5
1010
# DRF
1111
django-filter==1.1.0
1212
Markdown==2.6.11
13-
djangorestframework==3.7.7
13+
djangorestframework==3.11.2
1414
django-cors-headers==2.0.2
1515

1616
# crypto
1717
pycryptodome==3.6.5
18-
rsa==3.4.2
18+
rsa==4.1
1919
merkletools>=1.0.2
2020
pysha3>=1.0.2 #1.0b1
2121

2222
# Others
2323
django-jet==1.0.7
24+
xmltodict==0.12.0
2425

2526
#QRCode
26-
Pillow==4.2.1
27+
Pillow==8.1.2
2728
qrcode==5.3
2829

2930
# Proof of Existence (ETH)

rexchain/blockchain/managers.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,18 @@
1616
from django.core.cache import cache
1717
from core.utils import Hashcash
1818
from core.helpers import safe_set_cache, get_timestamp, logger_debug
19+
from core.connectors import ReachCore as PoE
20+
from nom151.models import ConservationCertificate
1921
from .helpers import genesis_hash_generator, GENESIS_INIT_DATA, get_genesis_merkle_root, CryptoTools
20-
from .utils import calculate_hash, PoE, pubkey_base64_to_rsa, ordered_data, iterate_and_order_json
22+
from .utils import calculate_hash, pubkey_base64_to_rsa, ordered_data, iterate_and_order_json
2123
from .querysets import (
2224
PayloadQueryset,
2325
TransactionQueryset,
2426
AddressQueryset,
2527
)
2628
from .RSAaddresses import AddressBitcoin
2729

30+
2831
logger = logging.getLogger('django_info')
2932

3033

@@ -67,9 +70,22 @@ def generate_next_block(self, hash_before, tx_queryset):
6770
str(new_block.timestamp), data_block["sum_hashes"])
6871
# Add Merkle Root
6972
new_block.merkleroot = data_block["merkleroot"]
70-
new_block.poetxid = "False"
73+
# Proof of Existennce layer
74+
connector = PoE()
75+
xml_response = connector.generate_proof(new_block.merkleroot)
76+
new_block.data["xml_response"] = xml_response
7177
# Save
7278
new_block.save()
79+
# Save response on a new table too
80+
81+
certificate = ConservationCertificate(
82+
folio=xml_response["Folio"],
83+
raw_document=xml_response["Constancia"],
84+
reference=new_block.merkleroot
85+
)
86+
certificate.block = new_block
87+
certificate.data["xml_response"] = xml_response
88+
certificate.save()
7389
return new_block
7490

7591

rexchain/blockchain/views.py

Lines changed: 6 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -31,56 +31,21 @@ class ValidateRxView(View):
3131

3232
def get(self, request, *args, **kwargs):
3333
hash_id = kwargs.get("hash_id")
34-
payload = transaction = None
34+
payload = tx = None
35+
template = "blockchain/validate.html"
3536
try:
3637
payload = Payload.objects.get(hash_id=hash_id)
38+
tx = payload.transaction
3739
except Exception as e:
3840
logger.info("[Validate ERROR]:{} type:{}".format(e, type(e)))
3941
# Try to get from transaction ID
4042
try:
41-
transaction = Transaction.objects.get(txid=hash_id)
43+
tx = Transaction.objects.get(txid=hash_id)
4244
except Exception as e:
4345
_message_error = "[Validate ERROR] Neither hash is from Payload nor Transaction:{} type:{}"
4446
logger.error(_message_error.format(e, type(e)))
45-
else:
46-
return render(request, self.template, {"poe": self.get_poe_data_context(transaction)})
47-
else:
48-
poe = self.get_poe_data_context(payload.transaction)
49-
return render(request, self.template, {"poe": poe})
50-
51-
return redirect("/")
52-
53-
def get_poe_data_context(self, transaction):
54-
''' Build poe data '''
55-
# Transaction TEST for validate TESTING only
56-
data_poe = {
57-
"received": "Aug. 25, 2018, 12:57 p.m.",
58-
"poe_url": ("https://live.blockcypher.com/bcy/tx/"
59-
"51998b337855f999718f3be0658af19f1615dd71dd8885a24e6c08bf201c257a/"),
60-
"hash": "51998b337855f999718f3be0658af19f1615dd71dd8885a24e6c08bf201c257a",
61-
"data_hex": "46e6ac758721c8f45d2a00de78d81df7861f655e41777f8e56b0556ea4bec0a9",
62-
"merkle_root": "46e6ac758721c8f45d2a00de78d81df7861f655e41777f8e56b0556ea4bec0a9",
63-
}
64-
65-
if transaction.block_id:
66-
block = transaction.block
67-
68-
if block.poetxid.strip() in ["True", "False", "", "Genesis"]:
69-
pass
70-
else:
71-
try:
72-
data_poe = {
73-
"received": block.timestamp.strftime('%Y-%m-%d'),
74-
"poe_url": "{}/dash/tx/{}/".format(settings.BASE_POE_URL, block.poetxid),
75-
"hash": block.poetxid,
76-
"data_hex": block.merkleroot,
77-
"merkle_root": block.merkleroot,
78-
}
79-
80-
except Exception as e:
81-
logger.info("[Get Poe Data ERROR]:{} type:{}".format(e, type(e)))
82-
83-
return data_poe
47+
return redirect("/")
48+
return render(request, template, {"tx": tx})
8449

8550

8651
def poe(request):

rexchain/core/connectors.py

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import base64
2+
import requests
3+
import subprocess # nosec B404
4+
import shlex
5+
import xmltodict
6+
7+
from tempfile import TemporaryDirectory as TempD
8+
9+
from django.conf import settings
10+
11+
from .helpers import logger
12+
13+
# GeneraConstancia Payload
14+
REQUEST_CERTIFICATE = """<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" \
15+
xmlns:xw="www.XMLWebServiceSoapHeaderAuth.net">
16+
<soap:Header>
17+
<xw:AuthSoapHd>
18+
<xw:Usuario>{user}</xw:Usuario>
19+
<xw:Clave>{passwd}</xw:Clave>
20+
<xw:Entidad>{entity}</xw:Entidad>
21+
</xw:AuthSoapHd>
22+
</soap:Header>
23+
<soap:Body>
24+
<xw:GeneraConstancia>
25+
<xw:referencia>{reference}</xw:referencia>
26+
<xw:solicitud>{doc_base64}</xw:solicitud>
27+
</xw:GeneraConstancia>
28+
</soap:Body>
29+
</soap:Envelope>"""
30+
31+
# ValidaConstancia Payload
32+
REQUEST_VALIDATE = """<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" \
33+
xmlns:xw="www.XMLWebServiceSoapHeaderAuth.net">
34+
<soap:Header>
35+
<xw:AuthSoapHd>
36+
<xw:Usuario>{user}</xw:Usuario>
37+
<xw:Clave>{passwd}</xw:Clave>
38+
<xw:Entidad>{entity}</xw:Entidad>
39+
</xw:AuthSoapHd>
40+
</soap:Header>
41+
<soap:Body>
42+
<xw:ValidaConstancia>
43+
<xw:referencia>{reference}</xw:referencia>
44+
<xw:constancia>{certificate}</xw:constancia>
45+
</xw:ValidaConstancia>
46+
</soap:Body>
47+
</soap:Envelope>"""
48+
49+
50+
class ReachCore:
51+
"""
52+
Class to handle rich core methods and connections
53+
referencia = "merkleroot" as a valid str sha256 hash
54+
solicitud = doc_file as a valid base64 str
55+
"""
56+
57+
ENTITY = settings.REACHCORE_ENTITY
58+
USER = settings.REACHCORE_USER
59+
PASS = settings.REACHCORE_PASS
60+
61+
TIMEOUT = 10
62+
HEADERS = {'content-type': 'text/xml'}
63+
64+
def __init__(self, **kwargs):
65+
""" Initialize vars and settings """
66+
67+
if settings.PRODUCTION:
68+
self.BASE = "https://nom151.advantage-security.com/wsnom151/webservice.asmx?WSDL"
69+
self.POLICY = "2.16.484.101.10.316.2.1.1.2.1"
70+
else:
71+
self.BASE = "https://pilot-psc.reachcore.com/wsnom151/webservice.asmx?WSDL"
72+
self.POLICY = "1.16.484.101.10.316.1.2"
73+
74+
def generate_proof(self, merkleroot):
75+
"""
76+
ReachCore endpoint [GeneraConstancia]
77+
merkleroot : Must be a valid sha256 str, as the merkle root is
78+
"""
79+
# Generates a temp directory where manipulate docs
80+
81+
with TempD() as temp_dir:
82+
doc_path = temp_dir + "/doc_body.tsq"
83+
request_file = None
84+
# Prepare the command for the request file
85+
command = (F"openssl ts -query -digest {merkleroot} -sha256 -no_nonce "
86+
F"-tspolicy {self.POLICY} -out {doc_path}")
87+
args = shlex.split(command)
88+
try:
89+
# Pass security params as check=True and shell = False - More details in Bandit B603
90+
process = subprocess.run(args, check=True, shell=False) # nosec B603
91+
except Exception as e:
92+
logger.info(F"[Error:{e} Generating File Request], stdout={process.stdout}")
93+
return None
94+
else:
95+
logger.info("Success Generated Request File")
96+
97+
# Read the file
98+
with open(doc_path, 'rb') as f:
99+
request_file = base64.b64encode(f.read())
100+
request_file = request_file.decode()
101+
102+
# Create body content
103+
body = REQUEST_CERTIFICATE.format(user=self.USER, passwd=self.PASS, entity=self.ENTITY,
104+
reference=merkleroot, doc_base64=request_file)
105+
# For debug only
106+
# logger.info(body)
107+
108+
try:
109+
# Send requests and get the content
110+
r = requests.post(self.BASE, data=body, headers=self.HEADERS, timeout=self.TIMEOUT)
111+
logger.info(F"Response: {r.status_code}")
112+
logger.info(F"{r.content}")
113+
114+
if r.status_code == 200:
115+
# Parse the file and generate readable json metadata
116+
parsed_result = xmltodict.parse(r.text)
117+
body = parsed_result["soap:Envelope"]["soap:Body"]
118+
metadata = body["GeneraConstanciaResponse"]["GeneraConstanciaResult"]
119+
metadata["xml_raw"] = r.text
120+
return metadata
121+
else:
122+
# TODO Try to generate next block
123+
# Execute a default behauvior or try to do it in other time
124+
return None
125+
126+
except Exception as e:
127+
logger.error(F"[Generate Proof Error]: {e}, type: {type(e)}, merkleroot: {merkleroot}")
128+
129+
def validate(self, certificate, merkleroot):
130+
""" Validate certificate using Reachcore validate endpoints """
131+
try:
132+
body = REQUEST_VALIDATE.format(user=self.USER, passwd=self.PASS, entity=self.ENTITY,
133+
reference=merkleroot, certificate=certificate)
134+
r = requests.post(self.BASE, data=body, headers=self.HEADERS, timeout=self.TIMEOUT)
135+
logger.info(F"Response: {r.status_code}")
136+
logger.info(F"{r.content}")
137+
if r.status_code == 200:
138+
parsed_result = xmltodict.parse(r.text)
139+
body = parsed_result["soap:Envelope"]["soap:Body"]
140+
metadata = body["ValidaConstanciaResponse"]["ValidaConstanciaResult"]
141+
metadata["xml_raw"] = r.text
142+
return metadata
143+
144+
else:
145+
# We might ask to user to try again
146+
return None
147+
148+
except Exception as e:
149+
logger.error(F"[Validate Certificate Fails]: {e}, type: {type(e)}, merkleroot: {merkleroot}")

rexchain/nom151/__init__.py

Whitespace-only changes.

rexchain/nom151/admin.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from django.contrib import admin
2+
3+
from .models import ConservationCertificate
4+
5+
6+
class ConservationCertificateAdmin(admin.ModelAdmin):
7+
pass
8+
9+
10+
admin.site.register(ConservationCertificate, ConservationCertificateAdmin)

rexchain/nom151/apps.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from django.apps import AppConfig
2+
3+
4+
class Nom151Config(AppConfig):
5+
name = 'nom151'

0 commit comments

Comments
 (0)