Compare commits

...

10 Commits

Author SHA1 Message Date
Cayo Puigdefabregas c5f97ef1e4 fix revocation_service not a list 2024-06-21 15:00:03 +02:00
Cayo Puigdefabregas 23c081502e fix list for array 2024-06-21 14:59:30 +02:00
Cayo Puigdefabregas 1b90d6966b add send_api in credential and fix 2024-06-21 14:59:08 +02:00
Cayo Puigdefabregas 8f15544fe5 fix schemas and credentials names 2024-06-21 12:08:42 +02:00
Cayo Puigdefabregas 338ab6e083 fix name EIssuer 2024-06-21 12:04:25 +02:00
Cayo Puigdefabregas 713ab080d6 rename ereuse-issuer 2024-06-21 12:03:30 +02:00
Cayo Puigdefabregas b960c87d83 get token from api dlt 2024-06-21 12:01:55 +02:00
Cayo Puigdefabregas fd8f404908 send credential as issuer to TA 2024-06-20 12:18:53 +02:00
Cayo Puigdefabregas a975d831f9 add credential_as_issuer in models 2024-06-20 10:00:07 +02:00
Cayo Puigdefabregas 65b4d17d82 add ereuse-issuer credential 2024-06-20 09:24:28 +02:00
10 changed files with 227 additions and 11 deletions

7
context/e-issuer.jsonld Normal file
View File

@ -0,0 +1,7 @@
{
"@context": {
"legalName": "https://idhub.pangea.org/context/#legalName",
"allowedSchemas": "https://idhub.pangea.org/context/#allowedSchemas",
"domain": "https://idhub.pangea.org/context/#domain"
}
}

View File

@ -0,0 +1,17 @@
# Generated by Django 4.2.5 on 2024-06-20 07:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('idhub', '0006_did_ether_address_did_ether_privkey'),
]
operations = [
migrations.AddField(
model_name='did',
name='credential_as_issuer',
field=models.TextField(null=True),
),
]

View File

@ -3,6 +3,7 @@ import ujson
import pytz import pytz
import hashlib import hashlib
import datetime import datetime
import requests
from collections import OrderedDict from collections import OrderedDict
from django.db import models from django.db import models
from django.conf import settings from django.conf import settings
@ -445,6 +446,7 @@ class DID(models.Model):
key_material = models.TextField() key_material = models.TextField()
ether_address = models.CharField(max_length=250, null=True) ether_address = models.CharField(max_length=250, null=True)
ether_privkey = models.CharField(max_length=250, null=True) ether_privkey = models.CharField(max_length=250, null=True)
api_token = models.CharField(max_length=250, null=True)
eidas1 = models.BooleanField(default=False) eidas1 = models.BooleanField(default=False)
user = models.ForeignKey( user = models.ForeignKey(
User, User,
@ -454,6 +456,7 @@ class DID(models.Model):
) )
# JSON-serialized DID document # JSON-serialized DID document
didweb_document = models.TextField() didweb_document = models.TextField()
credential_as_issuer = models.TextField(null=True)
@property @property
def is_organization_did(self): def is_organization_did(self):
@ -462,8 +465,7 @@ class DID(models.Model):
return False return False
def get_key_material(self): def get_key_material(self):
user = self.user or self.get_organization() return self.decrypt_data(self.key_material)
return user.decrypt_data(self.key_material)
def set_key_material(self, value): def set_key_material(self, value):
self.key_material = self.encrypt_data(value) self.key_material = self.encrypt_data(value)
@ -505,6 +507,9 @@ class DID(models.Model):
return Organization.objects.get(main=True) return Organization.objects.get(main=True)
def set_ether_address(self): def set_ether_address(self):
if self.ether_address:
return
priv, self.ether_address = generate_ether_address() priv, self.ether_address = generate_ether_address()
self.ether_privkey = self.encrypt_data(priv) self.ether_privkey = self.encrypt_data(priv)
@ -515,6 +520,69 @@ class DID(models.Model):
user.save() user.save()
return user.encrypt_data(value) return user.encrypt_data(value)
def decrypt_data(self, value):
user = self.user or self.get_organization()
return user.decrypt_data(value)
def send_api(self, data, token=settings.TOKEN_TA_API):
url = settings.VERIFIABLE_REGISTER_URL
if not url or not token:
return
headers = {"Authenticate": "Bearer {}".format(token)}
response = requests.post(url=url, data=data, headers=headers)
if response.status_code >= 300:
return
return response.json()
def send_credential_as_issuer_to_TA(self):
credential = self._render_credential_issuer()
response = self.send_api(credential)
self.credential_as_issuer = json.dumps(response)
def get_context(self):
format = "%Y-%m-%dT%H:%M:%SZ"
issuance_date = datetime.datetime.now().strftime(format)
credential_status_id = 'https://revocation.not.supported/'
org = Organization.objects.get(main=True)
allow_schemas = [x.url for x in Schemas.objects.all()]
context = {
"vc_id": "",
"id_credential": "",
"issuer_did": "",
"organization": "",
"validUntil": "",
"issuance_date": issuance_date,
"subject_did": self.did,
"legalName": org.name or "",
"allowedSchemas": allow_schemas,
"domain": self.org.domain,
"credential_status_id": credential_status_id,
}
return context
def _render_credential_issuer(self):
context = self.get_context()
template_name = "credentials/ereuse-issuer.json"
tmpl = get_template(template_name)
credential = ujson.loads(tmpl.render(context))
credential.pop("credentialStatus", None)
return ujson.dumps(credential)
def get_api_token(self):
if self.api_token:
return self.decrypt_data(self.api_token)
priv = self.decrypt_data(self.ether_privkey)
response = self.send_api(priv)
if not response:
return
self.api_token = self.encrypt_data(response)
return response
class Schemas(models.Model): class Schemas(models.Model):
@ -809,6 +877,13 @@ class VerificableCredential(models.Model):
new_dict[key] = value new_dict[key] = value
return new_dict return new_dict
def send_api(self):
token = self.issuer_did.get_api_token()
data = self.user.decrypt_data(self.data)
response = self.issuer_did.did.send_api(data, token=token)
if response:
self.subject_did.did.get_api_token()
class VCTemplate(models.Model): class VCTemplate(models.Model):
wkit_template_id = models.CharField(max_length=250) wkit_template_id = models.CharField(max_length=250)

View File

@ -2,13 +2,13 @@
"@context": [ "@context": [
"https://www.w3.org/2018/credentials/v1", "https://www.w3.org/2018/credentials/v1",
"https://idhub.pangea.org/context/base.jsonld", "https://idhub.pangea.org/context/base.jsonld",
"https://idhub.pangea.org/context/ereuse-roles.jsonld" "https://idhub.pangea.org/context/e-actors.jsonld"
], ],
"id": "{{ vc_id }}", "id": "{{ vc_id }}",
"type": [ "type": [
"VerifiableCredential", "VerifiableCredential",
"VerifiableAttestation", "VerifiableAttestation",
"EreuseRoles" "EActors"
], ],
"issuer": { "issuer": {
"id": "{{ issuer_did }}", "id": "{{ issuer_did }}",
@ -61,7 +61,7 @@
"revocationBitmapIndex": "{{ id_credential }}" "revocationBitmapIndex": "{{ id_credential }}"
}, },
"credentialSchema": { "credentialSchema": {
"id": "https://idhub.pangea.org/vc_schemas/ereuse-roles.json", "id": "https://idhub.pangea.org/vc_schemas/e-actors.json",
"type": "FullJsonSchemaValidator2021" "type": "FullJsonSchemaValidator2021"
} }
} }

View File

@ -0,0 +1,63 @@
{
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://idhub.pangea.org/context/base.jsonld",
"https://idhub.pangea.org/context/e-issuer.jsonld"
],
"id": "{{ vc_id }}",
"type": [
"VerifiableCredential",
"VerifiableAttestation",
"EIssuer"
],
"issuer": {
"id": "{{ issuer_did }}",
"name": "{{ organisation }}"
},
"issuanceDate": "{{ issuance_date }}",
"validFrom": "{{ issuance_date }}",
"validUntil": "{{ validUntil }}",
"name": [
{
"value": "Product and waste electronics operator claim",
"lang": "en"
},
{
"value": "Declaració d'operador de productes i residus electrònics",
"lang": "ca_ES"
},
{
"value": "Declaración de operador de productos y residuos electrónicos",
"lang": "es"
}
],
"description": [
{
"value": "Credential for e-product and e-waste operator claim",
"lang": "en"
},
{
"value": "Credencial per operador de productes i residus electrònics",
"lang": "ca_ES"
},
{
"value": "Credencial para operador de productos y residuos electrónicos",
"lang": "es"
}
],
"credentialSubject": {
"id": "{{ subject_did }}",
"legalName": "{{ legalName }}",
"allowedSchemas": "{{ allowedSchemas }}",
"domain": "{{ domain }}"
},
"credentialStatus": {
"id": "{{ credential_status_id }}",
"type": "RevocationBitmap2022",
"revocationBitmapIndex": "{{ id_credential }}"
},
"credentialSchema": {
"id": "https://idhub.pangea.org/vc_schemas/e-issuer.json",
"type": "FullJsonSchemaValidator2021"
}
}

View File

@ -110,11 +110,11 @@ def ServeDidView(request, did_id):
revocation_bitmap.serialize() revocation_bitmap.serialize()
) )
).decode('utf-8') ).decode('utf-8')
revocation_service = [{ # This is an object within a list. revocation_service = { # This is an object within a list.
"id": f"{id_did}#revocation", "id": f"{id_did}#revocation",
"type": "RevocationBitmap2022", "type": "RevocationBitmap2022",
"serviceEndpoint": f"data:application/octet-stream;base64,{encoded_revocation_bitmap}" "serviceEndpoint": f"data:application/octet-stream;base64,{encoded_revocation_bitmap}"
}] }
document["service"][0] = revocation_service document["service"][0] = revocation_service
# Serialize the DID + Revocation list in preparation for sending # Serialize the DID + Revocation list in preparation for sending
document = json.dumps(document) document = json.dumps(document)

View File

@ -1,7 +1,7 @@
{ {
"$id": "https://idhub.pangea.org/vc_schemas/ereuse-role.json", "$id": "https://idhub.pangea.org/vc_schemas/e-actors.json",
"$schema": "https://json-schema.org/draft/2020-12/schema", "$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "EreuseRoles", "title": "EActors",
"description": "Product and waste electronics operator claim, as proposed by eReuse.org", "description": "Product and waste electronics operator claim, as proposed by eReuse.org",
"name": [ "name": [
{ {

52
schemas/e-issuer.json Normal file
View File

@ -0,0 +1,52 @@
{
"$id": "https://idhub.pangea.org/vc_schemas/e-issuer.json",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "EIssuer",
"description": "This credential allow to holder to be issuer for a list of schemas",
"name": [
{
"value": "Allow to be issuer",
"lang": "en"
}
],
"type": "object",
"allOf": [
{
"$ref": "https://idhub.pangea.org/vc_schemas/ebsi/attestation.json"
},
{
"properties": {
"credentialSubject": {
"description": "Defines properties on credentialSubject",
"type": "object",
"properties": {
"id": {
"description": "Defines a unique identifier of the credential subject",
"type": "string",
"minLength": 1
},
"legalName": {
"description": "Legal name of the issuer",
"type": "string",
"minLength": 1
},
"domain": {
"type": "string",
"minLength": 1
},
"allowedSchemas": {
"description": "List of schemas",
"type": "array"
}
},
"required": [
"id",
"legalName",
"allowedSchemas",
"email"
]
}
}
}
]
}

View File

@ -242,3 +242,5 @@ CREATE_TEST_USERS = config('CREATE_TEST_USERS', default=False, cast=bool)
ENABLE_2FACTOR_AUTH = config('ENABLE_2FACTOR_AUTH', default=True, cast=bool) ENABLE_2FACTOR_AUTH = config('ENABLE_2FACTOR_AUTH', default=True, cast=bool)
COMMIT = config('COMMIT', default='') COMMIT = config('COMMIT', default='')
VERIFIABLE_REGISTER_URL = config('VERIFIABLE_REGISTER_URL', default='')
TOKEN_TA_API = config('TOKEN_TA_API', default='')