Compare commits

...

2 Commits

Author SHA1 Message Date
Cayo Puigdefabregas 7ab88ad290 add did view 2024-11-19 21:18:45 +01:00
Cayo Puigdefabregas f6d1cf719c add commands for setup to dlt 2024-11-19 21:18:45 +01:00
16 changed files with 475 additions and 21 deletions

View File

@ -245,3 +245,4 @@ COMMIT = config('COMMIT', default='')
# DLT SETTINGS # DLT SETTINGS
TOKEN_DLT = config("TOKEN_DLT", default=None) TOKEN_DLT = config("TOKEN_DLT", default=None)
API_DLT = config("API_DLT", default=None) API_DLT = config("API_DLT", default=None)
API_RESULVER = config("API_RESOLVER", default=None)

0
did/__init__.py Normal file
View File

3
did/admin.py Normal file
View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

6
did/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class DidConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "did"

View File

3
did/models.py Normal file
View File

@ -0,0 +1,3 @@
from django.db import models
# Create your models here.

View File

@ -0,0 +1,171 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ object.type }}</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css" rel="stylesheet" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css" />
<style>
body {
font-size: 0.875rem;
background-color: #f8f9fa;
display: flex;
flex-direction: column;
min-height: 100vh;
}
.custom-container {
background-color: #ffffff;
border-radius: 10px;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
padding: 30px;
margin-top: 30px;
flex-grow: 1;
}
.section-title {
color: #7a9f4f;
border-bottom: 2px solid #9cc666;
padding-bottom: 10px;
margin-bottom: 20px;
font-size: 1.5em;
}
.info-row {
margin-bottom: 10px;
}
.info-label {
font-weight: bold;
color: #545f71;
}
.info-value {
color: #333;
}
.component-card {
background-color: #f8f9fa;
border-left: 4px solid #9cc666;
margin-bottom: 15px;
transition: all 0.3s ease;
}
.component-card:hover {
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
transform: translateY(-2px);
}
.hash-value {
word-break: break-all;
background-color: #f3f3f3;
padding: 5px;
border-radius: 4px;
font-family: monospace;
font-size: 0.9em;
border: 1px solid #e0e0e0;
}
.card-title {
color: #9cc666;
}
.btn-primary {
background-color: #9cc666;
border-color: #9cc666;
padding: 0.1em 2em;
font-weight: 700;
}
.btn-primary:hover {
background-color: #8ab555;
border-color: #8ab555;
}
.btn-green-user {
background-color: #c7e3a3;
}
.btn-grey {
background-color: #f3f3f3;
}
footer {
background-color: #545f71;
color: #ffffff;
text-align: center;
padding: 10px 0;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="container custom-container">
<h1 class="text-center mb-4" style="color: #545f71;">{{ object.manufacturer }} {{ object.type }} {{ object.model }}</h1>
<div class="row">
<div class="col-lg-6">
<h2 class="section-title">Details</h2>
<div class="info-row row">
<div class="col-md-4 info-label">Phid</div>
<div class="col-md-8 info-value">
<div class="hash-value">{{ object.id }}</div>
</div>
</div>
<div class="info-row row">
<div class="col-md-4 info-label">Type</div>
<div class="col-md-8 info-value">{{ object.type }}</div>
</div>
{% if object.is_websnapshot %}
{% for snapshot_key, snapshot_value in object.last_user_evidence %}
<div class="info-row row">
<div class="col-md-4 info-label">{{ snapshot_key }}</div>
<div class="col-md-8 info-value">{{ snapshot_value|default:'' }}</div>
</div>
{% endfor %}
{% else %}
<div class="info-row row">
<div class="col-md-4 info-label">Manufacturer</div>
<div class="col-md-8 info-value">{{ object.manufacturer|default:'' }}</div>
</div>
<div class="info-row row">
<div class="col-md-4 info-label">Model</div>
<div class="col-md-8 info-value">{{ object.model|default:'' }}</div>
</div>
{% if user.is_authenticated %}
<div class="info-row row">
<div class="col-md-4 info-label">Serial Number</div>
<div class="col-md-8 info-value">{{ object.serial_number|default:'' }}</div>
</div>
{% endif %}
{% endif %}
</div>
<div class="col-lg-6">
<h2 class="section-title">Identifiers</h2>
{% for chid in object.hids %}
<div class="info-row">
<div class="hash-value">{{ chid|default:'' }}</div>
</div>
{% endfor %}
</div>
</div>
<h2 class="section-title mt-5">Components</h2>
<div class="row">
{% for component in object.components %}
<div class="col-md-6 mb-3">
<div class="card component-card">
<div class="card-body">
<h5 class="card-title">{{ component.type }}</h5>
<p class="card-text">
{% for component_key, component_value in component.items %}
{% if component_key not in 'actions,type' %}
{% if component_key != 'serialNumber' or user.is_authenticated %}
<strong>{{ component_key }}:</strong> {{ component_value }}<br />
{% endif %}
{% endif %}
{% endfor %}
</p>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
<footer>
<p>
&copy;{% now 'Y' %}eReuse. All rights reserved.
</p>
</footer>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.bundle.min.js"></script>
</body>
</html>

3
did/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

8
did/urls.py Normal file
View File

@ -0,0 +1,8 @@
from django.urls import path
from did import views
app_name = 'did'
urlpatterns = [
path("<str:pk>", views.PublicDeviceWebView.as_view(), name="device_web"),
]

60
did/views.py Normal file
View File

@ -0,0 +1,60 @@
from django.http import JsonResponse, Http404
from django.views.generic.base import TemplateView
from device.models import Device
class PublicDeviceWebView(TemplateView):
template_name = "device_web.html"
def get(self, request, *args, **kwargs):
self.pk = kwargs['pk']
self.object = Device(id=self.pk)
if not self.object.last_evidence:
raise Http404
if self.request.headers.get('Accept') == 'application/json':
return self.get_json_response()
return super().get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
self.object.initial()
context.update({
'object': self.object
})
return context
@property
def public_fields(self):
return {
'id': self.object.id,
'shortid': self.object.shortid,
'uuids': self.object.uuids,
'hids': self.object.hids,
'components': self.remove_serial_number_from(self.object.components),
}
@property
def authenticated_fields(self):
return {
'serial_number': self.object.serial_number,
'components': self.object.components,
}
def remove_serial_number_from(self, components):
for component in components:
if 'serial_number' in component:
del component['SerialNumber']
return components
def get_device_data(self):
data = self.public_fields
if self.request.user.is_authenticated:
data.update(self.authenticated_fields)
return data
def get_json_response(self):
device_data = self.get_device_data()
return JsonResponse(device_data)

View File

@ -1,10 +1,11 @@
import json
import time import time
import logging import logging
from django.conf import settings from django.conf import settings
from ereuseapi.methods import API from ereuseapi.methods import API
from dpp.models import Proof from dpp.models import Proof, UserDpp
logger = logging.getLogger('django') logger = logging.getLogger('django')
@ -29,22 +30,22 @@ PROOF_TYPE = {
} }
def connect_api(): def connect_api(user):
if not settings.TOKEN_DLT: dp = UserDpp.objects.filter(user=user).first()
if not dp:
return return
token_dlt = settings.TOKEN_DLT
api_dlt = settings.API_DLT api_dlt = settings.API_DLT
token_dlt = json.loads(dp).get("token_dlt")
if not api_dlt or not token_dlt:
logger.error("NOT POSSIBLE CONNECT WITH API DLT!!!")
return
return API(api_dlt, token_dlt, "ethereum") return API(api_dlt, token_dlt, "ethereum")
def register_dlt(chid, phid, proof_type=None): def register_dlt(api, chid, phid, proof_type=None):
api = connect_api()
if not api:
return
if proof_type: if proof_type:
return api.generate_proof( return api.generate_proof(
chid, chid,
@ -62,11 +63,8 @@ def register_dlt(chid, phid, proof_type=None):
) )
def issuer_dpp_dlt(dpp): def issuer_dpp_dlt(api, dpp):
phid = dpp.split(":")[0] phid = dpp.split(":")[0]
api = connect_api()
if not api:
return
return api.issue_passport( return api.issue_passport(
dpp, dpp,
@ -96,14 +94,14 @@ def save_proof(signature, ev_uuid, result, proof_type, user):
def register_device_dlt(chid, phid, ev_uuid, user): def register_device_dlt(chid, phid, ev_uuid, user):
token_dlt = settings.TOKEN_DLT
api_dlt = settings.API_DLT
if not token_dlt or not api_dlt:
return
cny_a = 1 cny_a = 1
while cny_a: while cny_a:
result = register_dlt(chid, phid) api = connect_api(user)
if not api:
cny_a = 0
return
result = register_dlt(api, chid, phid)
try: try:
assert result['Status'] == STATUS_CODE.get("Success") assert result['Status'] == STATUS_CODE.get("Success")
assert result['Data']['data']['timestamp'] assert result['Data']['data']['timestamp']
@ -148,7 +146,12 @@ def register_passport_dlt(chid, phid, ev_uuid, user):
cny_a = 1 cny_a = 1
while cny_a: while cny_a:
try: try:
result = issuer_dpp_dlt(dpp) api = connect_api(user)
if not api:
cny_a = 0
return
result = issuer_dpp_dlt(api, dpp)
cny_a = 0 cny_a = 0
except Exception as err: except Exception as err:
logger.error("ERROR API issue passport return: %s", err) logger.error("ERROR API issue passport return: %s", err)

View File

@ -0,0 +1,35 @@
import logging
import requests
from django.core.management.base import BaseCommand
from django.conf import settings
from user.models import Institution
logger = logging.getLogger('django')
class Command(BaseCommand):
help = "Insert a new Institution in DLT"
def add_arguments(self, parser):
parser.add_argument('domain', type=str, help='institution')
def handle(self, *args, **kwargs):
domain = kwargs.get("domain")
api = settings.API_RESOLVER
if not api
logger.error("you need set the var API_RESOLVER")
return
if "http" not in domain:
logger.error("you need put https:// in %s", domain)
return
api = api.strip("/")
domain = domain.strip("/")
data = {"url": domain}
url = api + '/registerURL'
res = requests.post(url, json=data)
print(res.json())

View File

@ -0,0 +1,72 @@
import json
import logging
from ereuseapi.methods import API
from django.conf import settings
from django.core.management.base import BaseCommand
from user.models import User, Institution
from dpp.models import UserDpp
logger = logging.getLogger('django')
class Command(BaseCommand):
help = "Insert users than are in Dlt with params: path of data set file"
def add_arguments(self, parser):
parser.add_argument('dataset_file', type=str, help='institution')
def handle(self, *args, **kwargs):
dataset_file = kwargs.get("dataset_file")
self.api_dlt = settings.API_DLT
self.institution = Institution.objects.filter().first()
if not self.api_dlt:
logger.error("you need set the var API_DLT")
return
self.api_dlt = self.api_dlt.strip("/")
with open(dataset_file) as f:
dataset = json.loads(f.read())
self.add_user(dataset)
def add_user(self, data):
email = data.get("email")
password = data.get("password")
api_token = data.get("api_token")
# ethereum = {"data": {"api_token": api_token}}
# data_eth = json.dumps(ethereum)
data_eth = json.dumps(api_token)
# TODO encrypt in the future
# api_keys_dlt = encrypt(password, data_eth)
api_keys_dlt = data_eth
user = User.objects.filter(email=email).first()
if not user:
user = User.objects.create(
email=email,
password=password,
institution = self.institution
)
roles = []
token_dlt = api_token
api = API(self.api_dlt, token_dlt, "ethereum")
result = api.check_user_roles()
if result.get('Status') == 200:
if 'Success' in result.get('Data', {}).get('status'):
rols = result.get('Data', {}).get('data', {})
roles = [(k, k) for k, v in rols.items() if v]
roles_dlt = json.dumps(roles)
UserDpp.objects.create(
roles_dlt=roles_dlt,
api_keys_dlt=api_keys_dlt,
user=user
)

View File

@ -0,0 +1,47 @@
import logging
import requests
from django.core.management.base import BaseCommand
from django.conf import settings
from dpp.models import MemberFederated
logger = logging.getLogger('django')
class Command(BaseCommand):
help = "Synchronize members of DLT"
def handle(self, *args, **kwargs):
api = settings.API_RESOLVER
if not api
logger.error("you need set the var API_RESOLVER")
return
api = api.strip("/")
url = api + '/getAll'
res = requests.get(url)
if res.status_code != 200:
return "Error, {}".format(res.text)
response = res.json()
members = response['url']
counter = members.pop('counter')
if counter <= MemberFederated.objects.count():
logger.info("Synchronize members of DLT -> All Ok")
return "All ok"
for k, v in members.items():
id = self.clean_id(k)
member = MemberFederated.objects.filter(dlt_id_provider=id).first()
if member:
if member.domain != v:
member.domain = v
member.save()
continue
MemberFederated.objects.create(dlt_id_provider=id, domain=v)
return res.text
def clean_id(self, id):
return int(id.split('DH')[-1])

View File

@ -0,0 +1,25 @@
# Generated by Django 5.0.6 on 2024-11-19 19:18
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("dpp", "0001_initial"),
]
operations = [
migrations.CreateModel(
name="MemberFederated",
fields=[
(
"dlt_id_provider",
models.IntegerField(primary_key=True, serialize=False),
),
("domain", models.CharField(max_length=256)),
("client_id", models.CharField(max_length=256)),
("client_secret", models.CharField(max_length=256)),
],
),
]

View File

@ -13,3 +13,20 @@ class Proof(models.Model):
issuer = models.ForeignKey(Institution, on_delete=models.CASCADE) issuer = models.ForeignKey(Institution, on_delete=models.CASCADE)
user = models.ForeignKey( user = models.ForeignKey(
User, on_delete=models.SET_NULL, null=True, blank=True) User, on_delete=models.SET_NULL, null=True, blank=True)
class MemberFederated(models.Model):
dlt_id_provider = models.IntegerField(primary_key=True)
domain = models.CharField(max_length=STR_EXTEND_SIZE)
# This client_id and client_secret is used for connected to this domain as
# a client and this domain then is the server of auth
client_id = models.CharField(max_length=STR_EXTEND_SIZE. null=True)
client_secret = models.CharField(max_length=STR_EXTEND_SIZE, null=True)
institution = models.ForeignKey(
Institution, on_delete=models.SET_NULL, null=True, blank=True)
class UserDpp(models.Model):
roles_dlt = models.TextField()
api_keys_dlt = models.TextField()
user = models.ForeignKey(User, on_delete=models.CASCADE)