Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…ert-issuer into feat/follow-data-integrity-proof
  • Loading branch information
lemoustachiste committed Feb 14, 2024
2 parents 601a216 + 19a2fc3 commit 3dc65ff
Show file tree
Hide file tree
Showing 10 changed files with 279 additions and 33 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[![Verifiable Credential Compliance result](https://badgen.net/badge/Verifiable%20Credentials%20v1/compliant/green?icon=https://www.w3.org/Icons/WWW/w3c_home_nb-v.svg)](https://www.blockcerts.org/vc-compliance-report.html)
[![Verifiable Credential Compliance result](https://badgen.net/badge/Verifiable%20Credentials%20v1/failure/red?icon=https://www.w3.org/Icons/WWW/w3c_home_nb-v.svg)](https://www.blockcerts.org/vc-compliance-report.html)
[![Build Status](https://travis-ci.org/blockchain-certificates/cert-issuer.svg?branch=master)](https://travis-ci.org/blockchain-certificates/cert-issuer)
[![PyPI version](https://badge.fury.io/py/cert-issuer.svg)](https://badge.fury.io/py/cert-issuer)

Expand Down
97 changes: 78 additions & 19 deletions cert_issuer/models/verifiable_credential.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@ def is_valid_url (url):
or parsed_url.netloc.__contains__(' '))
and url.__contains__(':'))

def is_V1_verifiable_credential (context):
ContextUrlsInstance = ContextUrls()
return ContextUrlsInstance.verifiable_credential_v1() in context

def is_V2_verifiable_credential (context):
ContextUrlsInstance = ContextUrls()
return ContextUrlsInstance.verifiable_credential_v2() in context


def validate_url (url):
if not is_valid_url (url):
raise ValueError('Invalid URL: {}'.format(url))
Expand All @@ -33,13 +42,15 @@ def validate_type (certificate_type):

def validate_context (context, type):
ContextUrlsInstance = ContextUrls()
vc_context_url = ContextUrlsInstance.verifiable_credential()
vc_context_url = [ContextUrlsInstance.verifiable_credential_v1(), ContextUrlsInstance.verifiable_credential_v2()]
blockcerts_valid_context_url = ContextUrlsInstance.v3_all()

if not isinstance(context, list):
raise ValueError('`@context` property must be an array')
if context[0] != vc_context_url:
raise ValueError('First @context declared must be {}, was given {}'.format(vc_context_url, context[0]))
if context[0] not in vc_context_url:
raise ValueError('First @context declared must be one of {}, was given {}'.format(vc_context_url, context[0]))
if is_V1_verifiable_credential(context) and is_V2_verifiable_credential(context):
raise ValueError('Cannot have both v1 and v2 Verifiable Credentials contexts defined in the context array')
if len(type) > 1 and len(context) == 1:
raise ValueError('A more specific type: {}, was detected, yet no context seems provided for that type'.format(type[1]))
if context[-1] not in blockcerts_valid_context_url:
Expand Down Expand Up @@ -88,6 +99,19 @@ def validate_expiration_date (certificate_expiration_date):
validate_date_RFC3339_string_format(certificate_expiration_date, 'expirationDate')
pass

def validate_valid_from_date (certificate_valid_from_date):
validate_date_RFC3339_string_format(certificate_valid_from_date, 'validFrom')
pass

def validate_valid_until_date (certificate_valid_until_date):
validate_date_RFC3339_string_format(certificate_valid_until_date, 'validUntil')
pass

def validate_date_set_after_other_date(second_date, first_date, second_date_key, first_date_key):
if not second_date > first_date:
raise ValueError('`{}` property must be a date set after `{}`'.format(second_date_key, first_date_key))
pass

def validate_credential_status (certificate_credential_status):
if not isinstance(certificate_credential_status, list):
certificate_credential_status = [certificate_credential_status]
Expand Down Expand Up @@ -123,22 +147,57 @@ def verify_credential(certificate_metadata):
except ValueError as err:
raise ValueError(err)

try:
# if undefined will throw KeyError
validate_issuance_date(certificate_metadata['issuanceDate'])
except KeyError:
raise ValueError('`issuanceDate` property must be defined')
except ValueError as err:
raise ValueError(err)

try:
# if undefined will throw KeyError
validate_expiration_date(certificate_metadata['expirationDate'])
except KeyError:
# optional property
pass
except ValueError as err:
raise ValueError(err)
if is_V1_verifiable_credential(certificate_metadata['@context']):
try:
# if undefined will throw KeyError
validate_issuance_date(certificate_metadata['issuanceDate'])
except KeyError:
raise ValueError('`issuanceDate` property must be defined')
except ValueError as err:
raise ValueError(err)

if 'expirationDate' in certificate_metadata:
try:
# if undefined will throw KeyError
validate_expiration_date(certificate_metadata['expirationDate'])
validate_date_set_after_other_date(
certificate_metadata['expirationDate'],
certificate_metadata['issuanceDate'],
'expirationDate',
'issuanceDate'
)
except KeyError:
# optional property
pass
except ValueError as err:
raise ValueError(err)

if is_V2_verifiable_credential(certificate_metadata['@context']):
try:
# if undefined will throw KeyError
validate_valid_from_date(certificate_metadata['validFrom'])
except KeyError:
# optional property
pass
except ValueError as err:
raise ValueError(err)

if 'validUntil' in certificate_metadata:
try:
# if undefined will throw KeyError
validate_valid_until_date(certificate_metadata['validUntil'])
if 'validFrom' in certificate_metadata:
validate_date_set_after_other_date(
certificate_metadata['validUntil'],
certificate_metadata['validFrom'],
'validUntil',
'validFrom'
)
except KeyError:
# optional property
pass
except ValueError as err:
raise ValueError(err)

try:
# if undefined will throw KeyError
Expand Down
15 changes: 8 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
cert-core>=3.0.0
cert-schema>=3.2.1
cert-schema>=3.5.1
merkletools==1.0.3
configargparse==0.13.0
glob2==0.6
mock==2.0.0
requests[security]>=2.18.4
pycoin==0.80
pyld==1.0.5
pyld==2.0.3
pysha3>=1.0.2
python-bitcoinlib>=0.10.1
tox>=3.0.0
Expand Down
2 changes: 0 additions & 2 deletions tests/models/test_integration_verify_credential_metadata.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import unittest
import mock
import copy

from cert_issuer.certificate_handlers import CertificateBatchHandler, CertificateV3Handler
from cert_issuer.models import CertificateHandler

credential_example = {
"@context": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import copy

from cert_issuer.certificate_handlers import CertificateBatchHandler, CertificateV3Handler
from cert_issuer.models import CertificateHandler

credential_example = {
"@context": [
Expand All @@ -17,7 +16,7 @@
"BlockcertsCredential"
],
"issuer": "https://raw.githubusercontent.com/AnthonyRonning/https-github.com-labnol-files/master/issuer-eth.json",
"issuanceDate": "2010-01-01T19:33:24Z",
"issuanceDate": "2024-01-01T19:33:24Z",
"credentialSubject": {
"id": "did:key:z6Mkq3L1jEDDZ5R7eT523FMLxC4k6MCpzqD7ff1CrkWpoJwM",
"alumniOf": {
Expand Down Expand Up @@ -141,6 +140,25 @@ def test_verify_expiration_date (self):

assert False

def test_verify_expiration_date_before_issuance_date_invalid (self):
candidate = copy.deepcopy(credential_example)
candidate['expirationDate'] = '2023-01-01T19:33:24Z'
handler = CertificateBatchHandler(
secret_manager=mock.Mock(),
certificate_handler=MockCertificateV3Handler(candidate),
merkle_tree=mock.Mock(),
config=mock.Mock()
)
handler.certificates_to_issue = {'metadata': mock.Mock()}

try:
handler.prepare_batch()
except Exception as e:
self.assertEqual(str(e), '`expirationDate` property must be a date set after `issuanceDate`')
return

assert False

def test_verify_credential_status (self):
candidate = copy.deepcopy(credential_example)
candidate['credentialStatus'] = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import unittest
import mock
import copy

from cert_issuer.certificate_handlers import CertificateBatchHandler, CertificateV3Handler

credential_example = {
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.blockcerts.org/schema/3.0/context.json"
],
"id": "urn:uuid:bbba8553-8ec1-445f-82c9-a57251dd731c",
"type": [
"VerifiableCredential",
"BlockcertsCredential"
],
"issuer": "https://raw.githubusercontent.com/AnthonyRonning/https-github.com-labnol-files/master/issuer-eth.json",
"validFrom": "2024-01-29T19:33:24Z",
"credentialSubject": {
"id": "did:key:z6Mkq3L1jEDDZ5R7eT523FMLxC4k6MCpzqD7ff1CrkWpoJwM",
}
}

class TestIssuanceBatchValidation (unittest.TestCase):
def test_verify_valid_from (self):
candidate = copy.deepcopy(credential_example)
candidate['validFrom'] = '20240130'
handler = CertificateBatchHandler(
secret_manager=mock.Mock(),
certificate_handler=MockCertificateV3Handler(candidate),
merkle_tree=mock.Mock(),
config=mock.Mock()
)
handler.certificates_to_issue = {'metadata': mock.Mock()}

try:
handler.prepare_batch()
except Exception as e:
self.assertEqual(str(e), '`validFrom` property must be a valid RFC3339 string. Value received: `20240130`')
return

assert False

def test_verify_valid_until (self):
candidate = copy.deepcopy(credential_example)
candidate['validUntil'] = '20200909'
handler = CertificateBatchHandler(
secret_manager=mock.Mock(),
certificate_handler=MockCertificateV3Handler(candidate),
merkle_tree=mock.Mock(),
config=mock.Mock()
)
handler.certificates_to_issue = {'metadata': mock.Mock()}

try:
handler.prepare_batch()
except Exception as e:
self.assertEqual(str(e), '`validUntil` property must be a valid RFC3339 string. Value received: `20200909`')
return

assert False

def test_verify_valid_until_before_validFrom_invalid (self):
candidate = copy.deepcopy(credential_example)
candidate['validUntil'] = '2024-01-01T19:33:24Z'
handler = CertificateBatchHandler(
secret_manager=mock.Mock(),
certificate_handler=MockCertificateV3Handler(candidate),
merkle_tree=mock.Mock(),
config=mock.Mock()
)
handler.certificates_to_issue = {'metadata': mock.Mock()}

try:
handler.prepare_batch()
except Exception as e:
self.assertEqual(str(e), '`validUntil` property must be a date set after `validFrom`')
return

assert False

class MockCertificateV3Handler(CertificateV3Handler):
def __init__(self, test_certificate):
self.test_certificate = test_certificate
print(self.test_certificate)
def _get_certificate_to_issue(self, data):
return self.test_certificate

if __name__ == '__main__':
unittest.main()
26 changes: 26 additions & 0 deletions tests/v3_certificate_validation/test_unit_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,21 @@ def test_validate_context_invalid_missing_context (self):

assert False

def test_validate_context_no_duplicate_vc_context (self):
candidate_context_url = [
'https://www.w3.org/2018/credentials/v1',
'https://www.w3.org/ns/credentials/v2',
'https://w3id.org/blockcerts/v3'
]
candidate_type = ['VerifiableCredential', 'BlockcertsCredential']
try:
validate_context(candidate_context_url, candidate_type)
except:
assert True
return

assert False

def test_validate_context_valid_w3idcanon (self):
candidate_context_url = ['https://www.w3.org/2018/credentials/v1', 'https://w3id.org/blockcerts/v3']
candidate_type = ['VerifiableCredential', 'BlockcertsCredential']
Expand All @@ -47,6 +62,17 @@ def test_validate_context_valid_w3idcanon (self):

assert True

def test_validate_context_valid_v2_w3idcanon (self):
candidate_context_url = ['https://www.w3.org/ns/credentials/v2', 'https://w3id.org/blockcerts/v3']
candidate_type = ['VerifiableCredential', 'BlockcertsCredential']
try:
validate_context(candidate_context_url, candidate_type)
except:
assert False
return

assert True

def test_validate_context_valid_blockcerts (self):
candidate_context_url = ['https://www.w3.org/2018/credentials/v1', 'https://www.blockcerts.org/schema/3.0/context.json']
candidate_type = ['VerifiableCredential', 'BlockcertsCredential']
Expand Down
27 changes: 27 additions & 0 deletions tests/v3_certificate_validation/test_unit_valid_from_date.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import unittest

from cert_issuer.models.verifiable_credential import validate_valid_from_date

class UnitValidationV3 (unittest.TestCase):
def test_validate_valid_from_date_invalid_RFC3339 (self):
candidate = '20200202'
try:
validate_valid_from_date(candidate)
except:
assert True
return

assert False

def test_validate_valid_from_date_valid_RFC3339 (self):
candidate = '2020-02-02T00:00:00Z'
try:
validate_valid_from_date(candidate)
except:
assert False
return

assert True

if __name__ == '__main__':
unittest.main()
Loading

0 comments on commit 3dc65ff

Please sign in to comment.