├── .gitignore ├── .travis.yml ├── LICENSE ├── MANIFEST.in ├── README.md ├── cert_schema ├── 1.1 │ ├── certificate-schema-v1-1.json │ └── issuer-schema-v1-1.json ├── 1.2 │ ├── assertion-1.2.json │ ├── blockchain-certificate-1.2.json │ ├── blockchain-receipt-1.2.json │ ├── certificate-1.2.json │ ├── certificate-document-1.2.json │ ├── context.json │ ├── issuer-1.2.json │ └── issuer-id-1.2.json ├── 2.0-alpha │ ├── context.json │ ├── issuerSchema.json │ ├── merkleProof2017Schema.json │ ├── recipientSchema.json │ ├── schema.json │ └── signatureLineSchema.json ├── 2.0 │ ├── context.json │ ├── issuerSchema.json │ ├── merkleProof2017Schema.json │ ├── obi.json │ ├── recipientSchema.json │ ├── schema.json │ └── signatureLineSchema.json ├── __init__.py ├── errors.py ├── jsonld_helpers.py └── schema_validator.py ├── docs ├── assertion-schema.md ├── certificate-document.md ├── certificate-schema.md ├── issuer-id.md ├── issuer.md ├── issuer_schema-2.md ├── issuer_schema.md ├── json-context.md ├── json-schema.md ├── merkleProofSignatureExtension_schema.md ├── open-badges.md ├── open_badge_v2_extensions.md ├── receipt.md ├── recipientProfileExtension_schema.md ├── schema-2.md ├── schema.md ├── schemas-2.md ├── schemas.md ├── signatureLineExtension_schema.md └── v1_x_schema.md ├── examples ├── 1.1 │ ├── sample_signed_cert-1.1.json │ └── sample_unsigned_cert-1.1.json ├── 1.2 │ ├── sample_invalid_cert-1.2.json │ ├── sample_signed_cert-1.2.json │ ├── sample_signed_cert_multiple_signers-1.2.json │ └── sample_unsigned_cert-1.2.json ├── 2.0-alpha │ ├── sample_valid.json │ ├── tampered_unmapped_fields.json │ └── tampered_unmapped_fields_vocab.json └── 2.0 │ └── bbba8553-8ec1-445f-82c9-a57251dd731c.json ├── release_package.sh ├── requirements.txt ├── run_tests.sh ├── scripts ├── generateMarkdown-experiment.js └── generate_markdown.js ├── setup.py ├── tests ├── __init__.py ├── test_jsonld_helpers.py └── test_schema_validator.py └── tox.ini /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | docs/_build/* 3 | .DS_Store 4 | 5 | venv/* 6 | site/* 7 | 8 | dist 9 | build 10 | 11 | conf.ini 12 | *.pyc 13 | 14 | .cache/ 15 | .coverage 16 | .eggs/ 17 | .tox/ 18 | *build/ 19 | 20 | *.egg-info* 21 | ~ 22 | ~ 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: python 3 | python: 4 | - "2.7" 5 | - "3.4" 6 | install: pip install tox-travis 7 | script: tox 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Media Lab Learning Initiative 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE *.md *.txt cert_schema/*/*.json -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/blockchain-certificates/cert-schema.svg?branch=master)](https://travis-ci.org/blockchain-certificates/cert-schema) 2 | [![PyPI version](https://badge.fury.io/py/cert-schema.svg)](https://badge.fury.io/py/cert-schema) 3 | 4 | # cert-schema 5 | 6 | Blockchain Certificate schemas extend those of [Open Badges](https://openbadgespec.org/). As with Open Badges, we've provided both a JSON-LD context and JSON schema. The purpose of the JSON-LD context is to map types to Internationalized Resource Identifiers (IRIs), providing semantic context for data. The JSON Schema is used for syntactic validation. 7 | 8 | This python package allows verification of a Blockchain Certificate against the JSON 9 | schemas as a convenience. This is not the same as verifying the contents of a certificate against what is stored 10 | on the blockchain. See the [cert-verifier-js](https://github.com/blockchain-certificates/cert-verifier-js) project. 11 | 12 | * [Blockcerts JSON Schema](docs/schema-2.md) 13 | 14 | ## Example 15 | 16 | The following is a Blockchain Certificate issued on the testnet Bitcoin network. 17 | 18 | ```json 19 | { 20 | "@context": [ 21 | "https://w3id.org/openbadges/v2", 22 | "https://w3id.org/blockcerts/v2" 23 | ], 24 | "type": "Assertion", 25 | "id": "urn:uuid:bbba8553-8ec1-445f-82c9-a57251dd731c", 26 | "badge": { 27 | "id": "urn:uuid:82a4c9f2-3588-457b-80ea-da695571b8fc", 28 | "type": "BadgeClass", 29 | "name": "Certificate of Accomplishment", 30 | "image": "data:image/png;base64,...", 31 | "description": "Lorem ipsum dolor sit amet, mei docendi concludaturque ad, cu nec partem graece. Est aperiam consetetur cu, expetenda moderatius neglegentur ei nam, suas dolor laudem eam an.", 32 | "criteria": { 33 | "narrative": "Nibh iriure ei nam, modo ridens neglegentur mel eu. At his cibo mucius." 34 | }, 35 | "issuer": { 36 | "id": "https://www.blockcerts.org/samples/2.0/issuer-testnet.json", 37 | "type": "Profile", 38 | "name": "University of Learning", 39 | "url": "https://www.issuer.org", 40 | "email": "contact@issuer.org", 41 | "revocationList": "https://www.blockcerts.org/samples/2.0/revocation-list-testnet.json", 42 | "image": "data:image/png;..." 43 | } 44 | }, 45 | "recipient": { 46 | "hashed": false, 47 | "identity": "eularia@landroth.org", 48 | "type": "email" 49 | }, 50 | "recipientProfile": { 51 | "type": [ 52 | "RecipientProfile", 53 | "Extension" 54 | ], 55 | "publicKey": "ecdsa-koblitz-pubkey:mtr98kany9G1XYNU74pRnfBQmaCg2FZLmc", 56 | "name": "Eularia Landroth" 57 | }, 58 | "issuedOn": "2017-06-29T14:58:57.461422+00:00", 59 | "verification": { 60 | "publicKey": "ecdsa-koblitz-pubkey:msBCHdwaQ7N2ypBYupkp6uNxtr9Pg76imj", 61 | "type": [ 62 | "MerkleProofVerification2017", 63 | "Extension" 64 | ] 65 | }, 66 | "signature": { 67 | "type": [ 68 | "MerkleProof2017", 69 | "Extension" 70 | ], 71 | "targetHash": "637ec732fa4b7b56f4c15a6a12680519a17a9e9eade09f5b424a48eb0e6f5ad0", 72 | "merkleRoot": "f029b45bb1a7b1f0b970f6de35344b73cccd16177b4c037acbc2541c7fc27078", 73 | "anchors": [ 74 | { 75 | "sourceId": "d75b7a5bdb3d5244b753e6b84e987267cfa4ffa7a532a2ed49ad3848be1d82f8", 76 | "type": "BTCOpReturn" 77 | } 78 | ], 79 | "proof": [ 80 | { 81 | "right": "11174e220fe74de907d1107e2a357e41434123f2948fc6b946fbfd7e3e3eecd1" 82 | } 83 | ] 84 | } 85 | } 86 | 87 | ``` 88 | 89 | ## Open Badge Extensions 90 | 91 | Details on [Blockcerts extensions to Open Badges](docs/open_badge_v2_extensions.md) 92 | 93 | ## Publishing package to pypi 94 | 95 | - [First time info](http://peterdowns.com/posts/first-time-with-pypi.html) 96 | - Publish script: `./release_package.sh` 97 | 98 | 99 | ## Unit tests 100 | 101 | This project uses tox to validate against several python environments. 102 | 103 | 1. Ensure you have an python environment. [Recommendations](https://github.com/blockchain-certificates/developer-common-docs/blob/master/virtualenv.md) 104 | 105 | 2. Run tests 106 | ``` 107 | ./run_tests.sh 108 | ``` 109 | 110 | 111 | ## Compile markdown from schema 112 | 113 | Note that json-schema-to-markdown doesn't handle ref schemas well, so you will 114 | need to manually update any 'undefined' references. 115 | 116 | `scripts/generate_markdown.js` builds the markdown-formatted schemas from json 117 | 118 | ## Contact 119 | 120 | Contact us at [the Blockcerts community forum](http://community.blockcerts.org/). 121 | 122 | -------------------------------------------------------------------------------- /cert_schema/1.1/certificate-schema-v1-1.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "id": "https://github.com/ml-learning/digital-certificates-schema/certificate-schema-v1.json", 4 | "title": "Certificate schema V1.1", 5 | "type": "object", 6 | "properties": { 7 | "certificate": { 8 | "type": "object", 9 | "properties": { 10 | "id": { 11 | "type": "string", 12 | "format": "uri", 13 | "description": "URI link to a JSON that describes the type of certificate. Default format is https://[domain]/criteria/[year]/[month]/[certificate_title].json." 14 | }, 15 | "image": { 16 | "type": "string", 17 | "description": "A base-64 encoded png image of the certificate's image.", 18 | "pattern": "data:image\/png;base64," 19 | }, 20 | "language": { 21 | "type": "string", 22 | "description": "Represents the ieft language and ieft country codes. Format is [ieft_language]-[IEFT_COUNTRY]. Backcompatible change to make this field not required.", 23 | "pattern": "[a-z]{2}-[A-Z]{2}" 24 | }, 25 | "subtitle": { 26 | "type": "object", 27 | "description": "Subtitle of the certificate.", 28 | "properties": { 29 | "content": { 30 | "type": "string", 31 | "description": "Content of the subtitle." 32 | }, 33 | "display": { 34 | "oneOf": [ 35 | { 36 | "type": "string" 37 | }, 38 | { 39 | "type": "boolean" 40 | } 41 | ], 42 | "description": "Flag that indicates whether to show or hide the subtitle in the viewer. Backcompatible change to allow 2 types that occurred in the wild before proper validation." 43 | } 44 | }, 45 | "required": [ 46 | "content", 47 | "display" 48 | ], 49 | "additionalProperties": false 50 | }, 51 | "title": { 52 | "type": "string", 53 | "description": "Title of the certificate." 54 | }, 55 | "issuer": { 56 | "type": "object", 57 | "description": "Details about the issuer of the certificate.", 58 | "properties": { 59 | "image": { 60 | "type": "string", 61 | "description": "A base-64 encoded png image of the issuer's logo.", 62 | "pattern": "data:image\/png;base64," 63 | }, 64 | "id": { 65 | "type": "string", 66 | "format": "uri", 67 | "description": "Link to a JSON that details the issuer's issuing and recovation keys. Default is https://[domain]/issuer/[org_abbr]-issuer.json. Included for (near) backward compatibility with open badges specification 1.1" 68 | }, 69 | "url": { 70 | "type": "string", 71 | "format": "uri", 72 | "description": "URI of the issuer's homepage" 73 | }, 74 | "name": { 75 | "type": "string", 76 | "description": "Name of the issuer." 77 | }, 78 | "email": { 79 | "type": "string", 80 | "format": "email", 81 | "description": "Email address of the issuer." 82 | } 83 | }, 84 | "required": [ 85 | "image", 86 | "id", 87 | "url", 88 | "name", 89 | "email" 90 | ], 91 | "additionalProperties": false 92 | }, 93 | "description": { 94 | "type": "string", 95 | "description": "Description of what the certificate represents. Usually one - three sentences long." 96 | } 97 | }, 98 | "additionalProperties": false, 99 | "required": [ 100 | "id", 101 | "image", 102 | "subtitle", 103 | "title", 104 | "issuer", 105 | "description" 106 | ] 107 | }, 108 | "assertion": { 109 | "type": "object", 110 | "properties": { 111 | "evidence": { 112 | "type": "string", 113 | "description": "Text, uri, etc. that shows evidence of the recipient's learning that the certificate represents. Can be left as an empty string if not used." 114 | }, 115 | "uid": { 116 | "type": "string", 117 | "description": "Unique identifier. By default it is created using the string of a BSON ObjectId(), yielding an identifier 24 characters long." 118 | }, 119 | "issuedOn": { 120 | "type": "string", 121 | "format": "date-time", 122 | "description": "Date the the certificate JSON was created." 123 | }, 124 | "id": { 125 | "type": "string", 126 | "format": "uri", 127 | "description": "URI that links to the certificate on the viewer. Default is https://[domain]/[uid]" 128 | }, 129 | "image:signature": { 130 | "type": "string", 131 | "description": "A base-64 encoded png image of the issuer's signature.", 132 | "pattern": "data:image\/png;base64," 133 | } 134 | }, 135 | "required": [ 136 | "evidence", 137 | "uid", 138 | "issuedOn", 139 | "id", 140 | "image:signature" 141 | ], 142 | "additionalProperties": false 143 | }, 144 | "verify": { 145 | "type": "object", 146 | "properties": { 147 | "attribute-signed": { 148 | "type": "string", 149 | "description": "Name of the attribute in the json that is signed by the issuer's private key. Default is 'uid', referring to the uid attribute." 150 | }, 151 | "type": { 152 | "type": "string", 153 | "description": "Name of the signing method. Default is 'ECDSA(secp256k1)', referring to the Bitcoin method of signing messages with the issuer's private key." 154 | }, 155 | "signer": { 156 | "type": "string", 157 | "format": "uri", 158 | "description": "URI where issuer's public key is presented. Default is https://[domain]/keys/[org-abbr]-certs-public-key.asc. Compatible with open badges specification v1.1. Ideally, we would change this to point to a JSON instead, so we could retire keys (similar to the way we handle the issuer ID), but for now we're sticking with the OBS 1.1." 159 | } 160 | }, 161 | "required": [ 162 | "attribute-signed", 163 | "type", 164 | "signer" 165 | ], 166 | "additionalProperties": false 167 | }, 168 | "recipient": { 169 | "type": "object", 170 | "properties": { 171 | "familyName": { 172 | "type": "string", 173 | "description": "Family name of the recipient." 174 | }, 175 | "identity": { 176 | "type": "string", 177 | "description": "String that represents a recipient's identity. By default, it is an email address." 178 | }, 179 | "type": { 180 | "type": "string", 181 | "description": "Type of value in the identity field. Default is 'email'." 182 | }, 183 | "hashed": { 184 | "oneOf": [ 185 | { 186 | "type": "string" 187 | }, 188 | { 189 | "type": "boolean" 190 | } 191 | ], 192 | "description": "Describes if the value in the identity field is hashed or not. Default is false, indicating that the identity is not hashed. Backcompatible change to allow 2 types that occurred in the wild before proper validation." 193 | }, 194 | "pubkey": { 195 | "type": "string", 196 | "description": "Bitcoin address (compressed public key, usually 24 characters) of the recipient." 197 | }, 198 | "givenName": { 199 | "type": "string", 200 | "description": "Given name of the recipient" 201 | } 202 | }, 203 | "required": [ 204 | "familyName", 205 | "identity", 206 | "type", 207 | "hashed", 208 | "pubkey", 209 | "givenName" 210 | ], 211 | "additionalProperties": false 212 | }, 213 | "signature": { 214 | "type": "string", 215 | "description": "String of signature created when the Bitcoin private key signs the value in the attribute-signed field." 216 | }, 217 | "extension": { 218 | "type": "object", 219 | "description": "Extension object that includes extra fields not in the standard.", 220 | "properties": { 221 | "assertion": { 222 | "type": "object", 223 | "properties": {} 224 | }, 225 | "verify": { 226 | "type": "object", 227 | "properties": {} 228 | }, 229 | "certificate": { 230 | "type": "object", 231 | "properties": {} 232 | }, 233 | "recipient": { 234 | "type": "object", 235 | "properties": {} 236 | } 237 | } 238 | } 239 | }, 240 | "required": [ 241 | "certificate", 242 | "assertion", 243 | "verify", 244 | "recipient" 245 | ], 246 | "additionalProperties": false 247 | } 248 | -------------------------------------------------------------------------------- /cert_schema/1.1/issuer-schema-v1-1.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "id": "https://github.com/ml-learning/digital-certificates-schema/issuer-schema-v2.json", 4 | "type": "object", 5 | "properties": { 6 | "issuer_key": { 7 | "type": "array", 8 | "items": { 9 | "type": "object", 10 | "properties": { 11 | "date": { 12 | "type": "string", 13 | "format": "date-time", 14 | "description": "Date time ISO-8601 format of the date that the keys were issued." 15 | }, 16 | "key": { 17 | "type": "string", 18 | "description": "Bitcoin address (compressed public key, usually 24 characters) that the issuer uses to issue the certificates." 19 | } 20 | }, 21 | "additionalProperties": false, 22 | "required": [ 23 | "date", 24 | "key" 25 | ] 26 | } 27 | }, 28 | "revocation_key": { 29 | "type": "array", 30 | "items": { 31 | "type": "object", 32 | "properties": { 33 | "date": { 34 | "type": "string", 35 | "format": "date-time", 36 | "description": "Date time ISO-8601 format of the date that the keys were issued." 37 | }, 38 | "key": { 39 | "type": "string", 40 | "description": "Bitcoin address (compressed public key, usually 24 characters) that the issuer uses to revoke the certificates." 41 | } 42 | }, 43 | "additionalProperties": false, 44 | "required": [ 45 | "date", 46 | "key" 47 | ] 48 | } 49 | } 50 | }, 51 | "additionalProperties": false, 52 | "required": [ 53 | "issuer_key", 54 | "revocation_key" 55 | ] 56 | } -------------------------------------------------------------------------------- /cert_schema/1.2/assertion-1.2.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "Blockchain Certificates Assertion Schema, Version 1.2", 4 | "id": "https://w3id.org/blockcerts/schema/1.2/assertion-1.2.json", 5 | "description": "Extends the Open Badges Assertion Schema for certificates on the blockchain", 6 | "type": "object", 7 | "definitions": { 8 | "JsonLdContext": { 9 | "description": "A link to a valid JSON-LD context file, that maps term names to contexts. Blockchain Certificate contexts may also define JSON-schema to validate Blockchain Certificates against. In a Blockchain Certificate Object, this will almost always be a string:uri to a single context file, but might rarely be an array of links or context objects instead. This schema also allows direct mapping of terms to IRIs by using an object as an option within an array.", 10 | "oneOf": [ 11 | { 12 | "type": "string" 13 | }, 14 | { 15 | "type": "array", 16 | "items": { 17 | "oneOf": [ 18 | { 19 | "type": "string" 20 | }, 21 | { 22 | "type": "object" 23 | }, 24 | { 25 | "type": "array" 26 | } 27 | ] 28 | } 29 | } 30 | ] 31 | }, 32 | "JsonLdType": { 33 | "description": "A type or an array of types that the Blockchain Certificate object represents. The first or only item should be 'Assertion', and any others should each be an IRI (usually a URL) corresponding to a definition of the type itself. In almost all cases, there will be only one type: 'Assertion'", 34 | "oneOf": [ 35 | { 36 | "type": "string" 37 | }, 38 | { 39 | "type": "array", 40 | "items": { 41 | "type": "string" 42 | } 43 | } 44 | ] 45 | } 46 | }, 47 | "properties": { 48 | "@context": { 49 | "$ref": "#/definitions/JsonLdContext" 50 | }, 51 | "type": { 52 | "$ref": "#/definitions/JsonLdType" 53 | }, 54 | "id": { 55 | "type": "string", 56 | "format": "uri", 57 | "description": "URI that links to the certificate on the viewer." 58 | }, 59 | "uid": { 60 | "type": "string", 61 | "pattern": "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}", 62 | "description": "Unique identifier, in GUID format. V1.2 change: string pattern changed to guid" 63 | }, 64 | "issuedOn": { 65 | "$ref": "https://openbadgespec.org/v1/schema/assertion.json#/definitions/DateTime", 66 | "description": "Date the the certificate JSON was created." 67 | }, 68 | "evidence": { 69 | "type": "string", 70 | "format": "uri", 71 | "description": "URL of the work that the recipient did to earn the achievement. This can be a page that links out to other pages if linking directly to the work is infeasible. V1.2 made this field optional, which is consistent with OBI spec." 72 | }, 73 | "expires": { 74 | "$ref": "https://openbadgespec.org/v1/schema/assertion.json#/definitions/DateTime", 75 | "description": "If the achievement has some notion of expiry, this indicates a date when a badge should no longer be considered valid." 76 | }, 77 | "image:signature": { 78 | "description": "A single signature image, or array of objects with fields image and jobTitle. V1.2 change: support multiple signatures", 79 | "oneOf": [ 80 | { 81 | "type": "string", 82 | "pattern": "data:image/png;base64,", 83 | "description": "Data URI; a base-64 encoded png image of the certificate's image. https://en.wikipedia.org/wiki/Data_URI_scheme" 84 | }, 85 | { 86 | "type": "array", 87 | "items": { 88 | "type": "object", 89 | "properties": { 90 | "image": { 91 | "type": "string", 92 | "pattern": "data:image/png;base64,", 93 | "description": "Data URI; a base-64 encoded png image of the certificate's image. https://en.wikipedia.org/wiki/Data_URI_scheme" 94 | }, 95 | "jobTitle": { 96 | "type": "string", 97 | "description": "Title of the undersigned. http://schema.org/Person#jobTitle" 98 | } 99 | } 100 | } 101 | } 102 | ] 103 | } 104 | }, 105 | "required": [ 106 | "type", 107 | "uid", 108 | "issuedOn", 109 | "id" 110 | ], 111 | "additionalProperties": true 112 | } 113 | -------------------------------------------------------------------------------- /cert_schema/1.2/blockchain-certificate-1.2.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "Blockchain Certificates Version 1.2 Schema", 4 | "id": "https://w3id.org/blockcerts/schema/1.2/blockchain-certificate-1.2.json", 5 | "description": "A schema for representing certificates on the blockchain", 6 | "type": "object", 7 | "definitions": { 8 | "JsonLdContext": { 9 | "description": "A link to a valid JSON-LD context file, that maps term names to contexts. Blockchain Certificate contexts may also define JSON-schema to validate Blockchain Certificates against. In a Blockchain Certificate Object, this will almost always be a string:uri to a single context file, but might rarely be an array of links or context objects instead. This schema also allows direct mapping of terms to IRIs by using an object as an option within an array.", 10 | "oneOf": [ 11 | { 12 | "type": "string" 13 | }, 14 | { 15 | "type": "array", 16 | "items": { 17 | "oneOf": [ 18 | { 19 | "type": "string" 20 | }, 21 | { 22 | "type": "object" 23 | }, 24 | { 25 | "type": "array" 26 | } 27 | ] 28 | } 29 | } 30 | ] 31 | }, 32 | "JsonLdType": { 33 | "description": "A type or an array of types that the Blockchain Certificate object represents. The first or only item should be 'BlockchainCertificate', and any others should each be an IRI (usually a URL) corresponding to a definition of the type itself. In almost all cases, there will be only one type: 'BlockchainCertificate'", 34 | "oneOf": [ 35 | { 36 | "type": "string" 37 | }, 38 | { 39 | "type": "array", 40 | "items": { 41 | "type": "string" 42 | } 43 | } 44 | ] 45 | }, 46 | "CertificateDocument": { 47 | "$ref": "https://w3id.org/blockcerts/schema/1.2/certificate-document-1.2.json" 48 | }, 49 | "BlockchainReceipt": { 50 | "$ref": "https://w3id.org/blockcerts/schema/1.2/blockchain-receipt-1.2.json" 51 | } 52 | }, 53 | "properties": { 54 | "@context": { 55 | "$ref": "#/definitions/JsonLdContext" 56 | }, 57 | "type": { 58 | "$ref": "#/definitions/JsonLdType" 59 | }, 60 | "document": { 61 | "$ref": "#/definitions/CertificateDocument" 62 | }, 63 | "receipt": { 64 | "$ref": "#/definitions/BlockchainReceipt" 65 | } 66 | }, 67 | "required": [ 68 | "@context", 69 | "type", 70 | "document", 71 | "receipt" 72 | ], 73 | "additionalProperties": true 74 | } 75 | -------------------------------------------------------------------------------- /cert_schema/1.2/blockchain-receipt-1.2.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "Blockchain Certificates Receipt Schema, Version 1.2", 4 | "id": "https://w3id.org/blockcerts/schema/1.2/blockchain-receipt-1.2.json", 5 | "description": "Provides evidence of the certificate on the blockchain, using the chainpoint v2 standard", 6 | "type": "object", 7 | "properties": { 8 | "@context": { 9 | "type": "string", 10 | "pattern": "https://w3id.org/chainpoint/v2", 11 | "description": "This should always be chainpoint v2 JSON LD context" 12 | }, 13 | "type": { 14 | "type": "string", 15 | "pattern": "ChainpointSHA256v2", 16 | "description": "type of hash. Currently the only supported hash type is SHA256, with chainpoint type ChainpointSHA256v2." 17 | }, 18 | "targetHash": { 19 | "type": "string", 20 | "pattern": "[A-Fa-f0-9]{64}", 21 | "description": "hash of item being verified. Currently the only supported hash type is SHA256, and the targetHash format is validated accordingly." 22 | }, 23 | "merkleRoot": { 24 | "type": "string", 25 | "pattern": "[A-Fa-f0-9]{64}", 26 | "description": "Merkle root value -- this is anchored to the blockchain. Currently the only supported hash type is SHA256, and merkleRoot format is validated accordingly." 27 | }, 28 | "proof": { 29 | "type": "array", 30 | "description": "how to walk the Merkle tree from the target item to the Merkle root", 31 | "items": { 32 | "type": "object", 33 | "properties": { 34 | "left": { 35 | "type": "string", 36 | "pattern": "[A-Fa-f0-9]{64}", 37 | "description": "value of left neighbor to combine into parent hash. Currently the only supported hash type is SHA256, and this value format is validated accordingly." 38 | }, 39 | "right": { 40 | "type": "string", 41 | "pattern": "[A-Fa-f0-9]{64}", 42 | "description": "value of right neighbor to combine into parent hash. Currently the only supported hash type is SHA256, and this value format is validated accordingly." 43 | 44 | } 45 | } 46 | } 47 | }, 48 | "anchors": { 49 | "type": "array", 50 | "description": "how the proof is anchored to the blockchain", 51 | "items": { 52 | "type": "object", 53 | "properties": { 54 | "type": { 55 | "type": "string", 56 | "pattern": "BTCOpReturn", 57 | "description": "type of anchor, e.g. BTCOpReturn. Currently the only supported value is BTCOpReturn." 58 | }, 59 | "sourceId": { 60 | "type": "string", 61 | "pattern": "[A-Fa-f0-9]{64}", 62 | "description": "How to lookup the proof on the blockchain. Currently this is expected to be the (value of the) Bitcoin transaction id, and this value format is validated accordingly" 63 | 64 | } 65 | }, 66 | "required": [ 67 | "sourceId" 68 | ] 69 | } 70 | } 71 | }, 72 | "required": [ 73 | "@context", 74 | "targetHash", 75 | "merkleRoot", 76 | "proof", 77 | "anchors" 78 | ] 79 | } 80 | -------------------------------------------------------------------------------- /cert_schema/1.2/certificate-1.2.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "Blockchain Certificates Certificate Schema, Version 1.2", 4 | "id": "https://w3id.org/blockcerts/schema/1.2/certificate-1.2.json", 5 | "description": "Extends the Open Badges Certificate Schema for certificates on the blockchain", 6 | "type": "object", 7 | "definitions": { 8 | "JsonLdContext": { 9 | "description": "A link to a valid JSON-LD context file, that maps term names to contexts. Blockchain Certificate contexts may also define JSON-schema to validate Blockchain Certificates against. In a Blockchain Certificate Object, this will almost always be a string:uri to a single context file, but might rarely be an array of links or context objects instead. This schema also allows direct mapping of terms to IRIs by using an object as an option within an array.", 10 | "oneOf": [ 11 | { 12 | "type": "string" 13 | }, 14 | { 15 | "type": "array", 16 | "items": { 17 | "oneOf": [ 18 | { 19 | "type": "string" 20 | }, 21 | { 22 | "type": "object" 23 | }, 24 | { 25 | "type": "array" 26 | } 27 | ] 28 | } 29 | } 30 | ] 31 | }, 32 | "JsonLdType": { 33 | "description": "A type or an array of types that the Blockchain Certificate object represents. The first or only item should be 'Certificate', and any others should each be an IRI (usually a URL) corresponding to a definition of the type itself. In almost all cases, there will be only one type: 'Certificate'", 34 | "oneOf": [ 35 | { 36 | "type": "string" 37 | }, 38 | { 39 | "type": "array", 40 | "items": { 41 | "type": "string" 42 | } 43 | } 44 | ] 45 | }, 46 | "Issuer": { 47 | "$ref": "https://w3id.org/blockcerts/schema/1.2/issuer-1.2.json" 48 | } 49 | }, 50 | "properties": { 51 | "@context": { 52 | "$ref": "#/definitions/JsonLdContext" 53 | }, 54 | "type": { 55 | "$ref": "#/definitions/JsonLdType" 56 | }, 57 | "id": { 58 | "type": "string", 59 | "format": "uri", 60 | "description": "URI link to a JSON that describes the type of certificate. Default format is https://[domain]/criteria/[year]/[month]/[certificate_title].json. V1.2 change: this field is optional." 61 | }, 62 | "name": { 63 | "type": "string", 64 | "description": "Name (or title) of the certificate. V1.2 change: renamed from 'title' to be consistent with OBI schema" 65 | }, 66 | "description": { 67 | "type": "string" 68 | }, 69 | "image": { 70 | "type": "string", 71 | "pattern": "data:image/png;base64,", 72 | "description": "Data URI; a base-64 encoded png image of the certificate's image. https://en.wikipedia.org/wiki/Data_URI_scheme" 73 | }, 74 | "criteria": { 75 | "type": "string", 76 | "format": "uri" 77 | }, 78 | "issuer": { 79 | "$ref": "#/definitions/Issuer" 80 | }, 81 | "alignment": { 82 | "$ref": "https://openbadgespec.org/v1/schema/badgeclass.json#/definitions/AlignmentArray" 83 | }, 84 | "tags": { 85 | "$ref": "https://openbadgespec.org/v1/schema/badgeclass.json#/definitions/TagsArray" 86 | }, 87 | "language": { 88 | "type": "string", 89 | "description": "Represents the ieft language and ieft country codes. Format is [ieft_language]-[IEFT_COUNTRY]. V1.2 changes: this field is optional", 90 | "pattern": "[a-z]{2}-[A-Z]{2}" 91 | }, 92 | "subtitle": { 93 | "type": "string", 94 | "description": "Subtitle of the certificate. V1.2 changes: this type is now string, and this field is optional" 95 | } 96 | }, 97 | "required": [ 98 | "name", 99 | "description", 100 | "image", 101 | "issuer" 102 | ], 103 | "additionalProperties": true 104 | } 105 | -------------------------------------------------------------------------------- /cert_schema/1.2/certificate-document-1.2.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "Certificate Document Version 1.2 Schema", 4 | "id": "https://w3id.org/blockcerts/schema/1.2/certificate-document-1.2.json", 5 | "description": "The complete certificate document, including the assertion, certificate, and issuer. Doesn't include the blockchain receipt. This part is hashed and placed on the blockchain", 6 | "type": "object", 7 | "definitions": { 8 | "JsonLdContext": { 9 | "description": "A link to a valid JSON-LD context file, that maps term names to contexts. Blockchain Certificate contexts may also define JSON-schema to validate Blockchain Certificates against. In a Blockchain Certificate Object, this will almost always be a string:uri to a single context file, but might rarely be an array of links or context objects instead. This schema also allows direct mapping of terms to IRIs by using an object as an option within an array.", 10 | "oneOf": [ 11 | { 12 | "type": "string" 13 | }, 14 | { 15 | "type": "array", 16 | "items": { 17 | "oneOf": [ 18 | { 19 | "type": "string" 20 | }, 21 | { 22 | "type": "object" 23 | }, 24 | { 25 | "type": "array" 26 | } 27 | ] 28 | } 29 | } 30 | ] 31 | }, 32 | "JsonLdType": { 33 | "description": "A type or an array of types that the Blockchain Certificate object represents. The first or only item should be 'CertificateDocument', and any others should each be an IRI (usually a URL) corresponding to a definition of the type itself. In almost all cases, there will be only one type: 'CertificateDocument'", 34 | "oneOf": [ 35 | { 36 | "type": "string" 37 | }, 38 | { 39 | "type": "array", 40 | "items": { 41 | "type": "string" 42 | } 43 | } 44 | ] 45 | }, 46 | "Certificate": { 47 | "$ref": "https://w3id.org/blockcerts/schema/1.2/certificate-1.2.json" 48 | }, 49 | "Assertion": { 50 | "$ref": "https://w3id.org/blockcerts/schema/1.2/assertion-1.2.json" 51 | }, 52 | "VerificationObject": { 53 | "type": "object", 54 | "description": "V1.2 notice: the Blockchain Certificates VerificationObject will change in the next schema version to be consistent with OBI VerificationObjects. This work is in progress.", 55 | "properties": { 56 | "attribute-signed": { 57 | "type": "string", 58 | "description": "Name of the attribute in the json that is signed by the issuer's private key. Default is 'uid', referring to the uid attribute." 59 | }, 60 | "type": { 61 | "type": "string", 62 | "enum": [ 63 | "hosted", 64 | "signed", 65 | "ECDSA(secp256k1)" 66 | ], 67 | "description": "Name of the signing method. Default is 'ECDSA(secp256k1)', referring to the Blockchain Certificates method of signing messages with the issuer's private key." 68 | }, 69 | "signer": { 70 | "type": "string", 71 | "format": "uri", 72 | "description": "URI where issuer's public key is presented. Default is https://[domain]/keys/[org-abbr]-certs-public-key.asc. V1.2 change: this field is optional" 73 | } 74 | }, 75 | "required": [ 76 | "attribute-signed", 77 | "type" 78 | ] 79 | }, 80 | "Recipient": { 81 | "type": "object", 82 | "properties": { 83 | "familyName": { 84 | "type": "string", 85 | "description": "Family name of the recipient. http://schema.org/Person#familyName" 86 | }, 87 | "identity": { 88 | "type": "string", 89 | "description": "String that represents a recipient's identity. By default, it is an email address." 90 | }, 91 | "type": { 92 | "type": "string", 93 | "description": "Type of value in the identity field. Default is 'email'." 94 | }, 95 | "hashed": { 96 | "type": "boolean", 97 | "description": "Describes if the value in the identity field is hashed or not. We strongly recommend that the issuer hash the identy to protect the recipient." 98 | }, 99 | "salt": { 100 | "type": "string", 101 | "description": "per the OBI standard, if the recipient identity is hashed, then this should contain the string used to salt the hash" 102 | }, 103 | "publicKey": { 104 | "type": "string", 105 | "description": "Bitcoin address (compressed public key, usually 24 characters) of the recipient. V1.2 change: renamed from pubkey" 106 | }, 107 | "revocationKey": { 108 | "type": "string", 109 | "description": "Issuer revocation key for the recipient, optional. Bitcoin address (compressed public key, usually 24 characters) of the recipient." 110 | }, 111 | "givenName": { 112 | "type": "string", 113 | "description": "Given name of the recipient. http://schema.org/Person#givenName" 114 | } 115 | }, 116 | "required": [ 117 | "type", 118 | "familyName", 119 | "identity", 120 | "hashed", 121 | "publicKey", 122 | "givenName" 123 | ], 124 | "additionalProperties": true 125 | } 126 | }, 127 | "properties": { 128 | "@context": { 129 | "$ref": "#/definitions/JsonLdContext" 130 | }, 131 | "type": { 132 | "$ref": "#/definitions/JsonLdType" 133 | }, 134 | "certificate": { 135 | "$ref": "#/definitions/Certificate" 136 | }, 137 | "assertion": { 138 | "$ref": "#/definitions/Assertion" 139 | }, 140 | "verify": { 141 | "$ref": "#/definitions/VerificationObject" 142 | }, 143 | "recipient": { 144 | "$ref": "#/definitions/Recipient" 145 | } 146 | }, 147 | "required": [ 148 | "type", 149 | "certificate", 150 | "assertion", 151 | "verify", 152 | "recipient" 153 | ], 154 | "additionalProperties": true 155 | } 156 | -------------------------------------------------------------------------------- /cert_schema/1.2/context.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": [ 3 | { 4 | "id": "@id", 5 | "type": "@type", 6 | "bc": "https://w3id.org/blockcerts#", 7 | "obi": "https://w3id.org/openbadges#", 8 | "cp": "https://w3id.org/chainpoint#", 9 | "extensions": "https://w3id.org/openbadges/extensions#", 10 | "validation": "obi:validation", 11 | "xsd": "http://www.w3.org/2001/XMLSchema#", 12 | "schema": "http://schema.org/", 13 | "sec": "https://w3id.org/security#", 14 | "Assertion": "bc:Assertion", 15 | "Certificate": "bc:Certificate", 16 | "Issuer": "bc:Issuer", 17 | "BlockchainCertificate": "bc:BlockchainCertificate", 18 | "CertificateDocument": "bc:CertificateDocument", 19 | "issuer": { 20 | "@id": "bc:issuer", 21 | "@type": "@id" 22 | }, 23 | "recipient": { 24 | "@id": "bc:recipient", 25 | "@type": "@id" 26 | }, 27 | "blockchaincertificate": { 28 | "@id": "bc:blockchaincertificate", 29 | "@type": "@id" 30 | }, 31 | "certificate": { 32 | "@id": "bc:certificate", 33 | "@type": "@id" 34 | }, 35 | "document": { 36 | "@id": "bc:document", 37 | "@type": "@id" 38 | }, 39 | "assertion": { 40 | "@id": "bc:assertion", 41 | "@type": "@id" 42 | }, 43 | "verify": { 44 | "@id": "bc:verify", 45 | "@type": "@id" 46 | }, 47 | "recipient": { 48 | "@id": "bc:recipient", 49 | "@type": "@id" 50 | }, 51 | "receipt": { 52 | "@id": "bc:receipt", 53 | "@type": "@id" 54 | }, 55 | "publicKey": { 56 | "@id": "bc:publicKey" 57 | }, 58 | "revocationKey": { 59 | "@id": "bc:revocationKey" 60 | }, 61 | "image:signature": { 62 | "@id": "bc:image:signature" 63 | }, 64 | "signature": { 65 | "@id": "bc:signature" 66 | }, 67 | "familyName": { 68 | "@id": "schema:familyName" 69 | }, 70 | "givenName": { 71 | "@id": "schema:givenName" 72 | }, 73 | "jobTitle": { 74 | "@id": "schema:jobTitle" 75 | }, 76 | "signer": { 77 | "@id": "bc:signer", 78 | "@type": "@id" 79 | }, 80 | "attribute-signed": { 81 | "@id": "bc:attribute-signed" 82 | }, 83 | "ECDSA(secp256k1)": "bc:SignedBadge", 84 | "subtitle": { 85 | "@id": "bc:subtitle" 86 | }, 87 | "email": "schema:email", 88 | "hashed": { 89 | "@id": "obi:hashed", 90 | "@type": "xsd:boolean" 91 | }, 92 | "image": { 93 | "@id": "schema:image", 94 | "@type": "@id" 95 | }, 96 | "salt": { 97 | "@id": "obi:salt" 98 | }, 99 | "identity": { 100 | "@id": "obi:identityHash" 101 | }, 102 | "issuedOn": { 103 | "@id": "obi:issueDate", 104 | "@type": "xsd:dateTime" 105 | }, 106 | "expires": { 107 | "@id": "sec:expiration", 108 | "@type": "xsd:dateTime" 109 | }, 110 | "evidence": { 111 | "@id": "obi:evidence", 112 | "@type": "@id" 113 | }, 114 | "criteria": { 115 | "@id": "obi:criteria", 116 | "@type": "@id" 117 | }, 118 | "tags": { 119 | "@id": "schema:keywords" 120 | }, 121 | "alignment": { 122 | "@id": "obi:alignment", 123 | "@type": "@id" 124 | }, 125 | "revocationList": { 126 | "@id": "obi:revocationList", 127 | "@type": "@id" 128 | }, 129 | "name": { 130 | "@id": "schema:name" 131 | }, 132 | "description": { 133 | "@id": "schema:description" 134 | }, 135 | "url": { 136 | "@id": "schema:url", 137 | "@type": "@id" 138 | }, 139 | "uid": { 140 | "@id": "obi:uid" 141 | }, 142 | "revocationList": "obi:revocationList", 143 | "TypeValidation": "obi:TypeValidation", 144 | "FrameValidation": "obi:FrameValidation", 145 | "validatesType": "obi:validatesType", 146 | "validationSchema": "obi:validationSchema", 147 | "validationFrame": "obi:validationFrame", 148 | "ChainpointSHA224v2": "cp:ChainpointSHA224v2", 149 | "ChainpointSHA256v2": "cp:ChainpointSHA256v2", 150 | "ChainpointSHA384v2": "cp:ChainpointSHA384v2", 151 | "ChainpointSHA512v2": "cp:ChainpointSHA512v2", 152 | "ChainpointSHA3-224v2": "cp:ChainpointSHA3-224v2", 153 | "ChainpointSHA3-256v2": "cp:ChainpointSHA3-256v2", 154 | "ChainpointSHA3-384v2": "cp:ChainpointSHA3-384v2", 155 | "ChainpointSHA3-512v2": "cp:ChainpointSHA3-512v2", 156 | "BTCOpReturn": "cp:BTCOpReturn", 157 | "targetHash": "cp:targetHash", 158 | "merkleRoot": "cp:merkleRoot", 159 | "proof": "cp:proof", 160 | "anchors": "cp:anchors", 161 | "sourceId": "cp:sourceId", 162 | "right": "cp:right", 163 | "left": "cp:left" 164 | } 165 | ], 166 | "validation": [ 167 | { 168 | "type": "TypeValidation", 169 | "validatesType": "Assertion", 170 | "validationSchema": "https://w3id.org/blockcerts/schema/1.2/assertion-1.2.json" 171 | }, 172 | { 173 | "type": "TypeValidation", 174 | "validatesType": "Certificate", 175 | "validationSchema": "https://w3id.org/blockcerts/schema/1.2/certificate-1.2.json" 176 | }, 177 | { 178 | "type": "TypeValidation", 179 | "validatesType": "Issuer", 180 | "validationSchema": "https://w3id.org/blockcerts/schema/1.2/issuer-1.2.json" 181 | }, 182 | { 183 | "type": "TypeValidation", 184 | "validatesType": "CertificateDocument", 185 | "validationSchema": "https://w3id.org/blockcerts/schema/1.2/certificate-document-1.2.json" 186 | }, 187 | { 188 | "type": "TypeValidation", 189 | "validatesType": "BlockchainCertificate", 190 | "validationSchema": "https://w3id.org/blockcerts/schema/1.2/blockchain-certificate-1.2.json" 191 | }, 192 | { 193 | "type": "TypeValidation", 194 | "validatesType": "BlockchainReceipt", 195 | "validationSchema": "https://w3id.org/blockcerts/schema/1.2/blockchain-receipt-1.2.json" 196 | } 197 | ] 198 | } 199 | -------------------------------------------------------------------------------- /cert_schema/1.2/issuer-1.2.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "Blockchain Certificates Issuer Schema, Version 1.2", 4 | "id": "https://w3id.org/blockcerts/schema/1.2/issuer-1.2.json", 5 | "description": "Extends the Open Badges Issuer Schema for certificates on the blockchain", 6 | "type": "object", 7 | "definitions": { 8 | "JsonLdContext": { 9 | "description": "A link to a valid JSON-LD context file, that maps term names to contexts. Blockchain Certificate contexts may also define JSON-schema to validate Blockchain Certificates against. In a Blockchain Certificate Object, this will almost always be a string:uri to a single context file, but might rarely be an array of links or context objects instead. This schema also allows direct mapping of terms to IRIs by using an object as an option within an array.", 10 | "oneOf": [ 11 | { 12 | "type": "string" 13 | }, 14 | { 15 | "type": "array", 16 | "items": { 17 | "oneOf": [ 18 | { 19 | "type": "string" 20 | }, 21 | { 22 | "type": "object" 23 | }, 24 | { 25 | "type": "array" 26 | } 27 | ] 28 | } 29 | } 30 | ] 31 | }, 32 | "JsonLdType": { 33 | "description": "A type or an array of types that the Blockchain Certificate object represents. The first or only item should be 'Issuer', and any others should each be an IRI (usually a URL) corresponding to a definition of the type itself. In almost all cases, there will be only one type: 'Issuer'", 34 | "oneOf": [ 35 | { 36 | "type": "string" 37 | }, 38 | { 39 | "type": "array", 40 | "items": { 41 | "type": "string" 42 | } 43 | } 44 | ] 45 | }, 46 | "BCBadgeImage": { 47 | "description": "An image representative of the entity. This overrides BadgeImage from OBI because oneOf, compared to anyOf, was failing validation", 48 | "anyOf": [ 49 | { 50 | "$ref": "https://openbadgespec.org/v1/schema/issuer.json#/definitions/ImageDataUrl" 51 | }, 52 | { 53 | "type": "string", 54 | "format": "uri" 55 | } 56 | ] 57 | } 58 | }, 59 | "properties": { 60 | "@context": { 61 | "$ref": "#/definitions/JsonLdContext" 62 | }, 63 | "type": { 64 | "$ref": "#/definitions/JsonLdType" 65 | }, 66 | "id": { 67 | "type": "string", 68 | "format": "uri", 69 | "description": "Link to a JSON that details the issuer's issuing and recovation keys. Default is https://[domain]/issuer/[org_abbr]-issuer.json. Included for (near) backward compatibility with open badges specification 1.1" 70 | }, 71 | "image": { 72 | "$ref": "#/definitions/BCBadgeImage" 73 | }, 74 | "name": { 75 | "description": "Human-readable name of the issuing entity", 76 | "type": "string" 77 | }, 78 | "url": { 79 | "description": "The URL of the issuer's website or homepage", 80 | "type": "string", 81 | "format": "uri" 82 | }, 83 | "description": { 84 | "type": "string", 85 | "description": "A text description of the issuing organization" 86 | }, 87 | "email": { 88 | "type": "string", 89 | "format": "email", 90 | "description": "Contact address for the individual or organization." 91 | }, 92 | "revocationList": { 93 | "type": "string", 94 | "format": "uri" 95 | } 96 | }, 97 | "required": [ 98 | "name", 99 | "url", 100 | "id" 101 | ], 102 | "additionalProperties": true 103 | } 104 | -------------------------------------------------------------------------------- /cert_schema/1.2/issuer-id-1.2.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "id": "https://w3id.org/blockcerts/schema/1.2/issuer-id-1.2.json", 4 | "type": "object", 5 | "properties": { 6 | "issuerKeys": { 7 | "type": "array", 8 | "description": "list of issuer keys, listed in descending date order (most recent first). V1.2 change: renamed from issuer_key, added optional invalidated field.", 9 | "items": { 10 | "type": "object", 11 | "properties": { 12 | "date": { 13 | "type": "string", 14 | "format": "date-time", 15 | "description": "ISO-8601 formatted date time the key was activated." 16 | }, 17 | "key": { 18 | "type": "string", 19 | "description": "Bitcoin address (compressed public key, usually 24 characters) that the issuer uses to issue the certificates." 20 | }, 21 | "invalidated": { 22 | "type": "string", 23 | "format": "date-time", 24 | "description": "Optional ISO-8601 formatted date time the key was invalidated." 25 | } 26 | }, 27 | "additionalProperties": false, 28 | "required": [ 29 | "date", 30 | "key" 31 | ] 32 | } 33 | }, 34 | "revocationKeys": { 35 | "type": "array", 36 | "description": "list of revocation keys, listed in descending date order (most recent first). V1.2 changes: renamed from revocation_key, added optional invalidated field.", 37 | "items": { 38 | "type": "object", 39 | "properties": { 40 | "date": { 41 | "type": "string", 42 | "format": "date-time", 43 | "description": "ISO-8601 formatted date time the key was activated." 44 | }, 45 | "key": { 46 | "type": "string", 47 | "description": "Bitcoin address (compressed public key, usually 24 characters) that the issuer uses to revoke the certificates." 48 | }, 49 | "invalidated": { 50 | "type": "string", 51 | "format": "date-time", 52 | "description": "Optional ISO-8601 formatted date time the key was invalidated." 53 | } 54 | }, 55 | "additionalProperties": false, 56 | "required": [ 57 | "date", 58 | "key" 59 | ] 60 | } 61 | }, 62 | "id": { 63 | "description": "The URL of the issuer's website or homepage", 64 | "type": "string", 65 | "format": "uri" 66 | }, 67 | "name": { 68 | "description": "Human-readable name of the issuing entity", 69 | "type": "string" 70 | }, 71 | "email": { 72 | "type": "string", 73 | "format": "email", 74 | "description": "Contact address for the individual or organization." 75 | }, 76 | "url": { 77 | "description": "The URL where the issuer's certificates can be found", 78 | "type": "string", 79 | "format": "uri" 80 | }, 81 | "introductionURL": { 82 | "description": "The URL hosting the issuer's introduction endpoint", 83 | "type": "string", 84 | "format": "uri" 85 | }, 86 | "image": { 87 | "type": "string", 88 | "pattern": "data:image/png;base64,", 89 | "description": "Data URI; a base-64 encoded png image of the issuer's image. https://en.wikipedia.org/wiki/Data_URI_scheme" 90 | } 91 | }, 92 | "additionalProperties": false, 93 | "required": [ 94 | "issuerKeys", 95 | "revocationKeys", 96 | "id", 97 | "name", 98 | "email", 99 | "url", 100 | "introductionURL", 101 | "image" 102 | ] 103 | } 104 | -------------------------------------------------------------------------------- /cert_schema/2.0-alpha/context.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": { 3 | "id": "@id", 4 | "type": "@type", 5 | "bc": "https://w3id.org/blockcerts#", 6 | "obi": "https://w3id.org/openbadges#", 7 | "cp": "https://w3id.org/chainpoint#", 8 | "schema": "http://schema.org/", 9 | "sec": "https://w3id.org/security#", 10 | "xsd": "http://www.w3.org/2001/XMLSchema#", 11 | 12 | "MerkleProof2017": "sec:MerkleProof2017", 13 | 14 | "RecipientProfile": "bc:RecipientProfile", 15 | "SignatureLine": "bc:SignatureLine", 16 | "MerkleProofVerification2017": "bc:MerkleProofVerification2017", 17 | 18 | "recipientProfile": "bc:recipientProfile", 19 | "signatureLines": "bc:signatureLines", 20 | "introductionUrl": { "@id": "bc:introductionUrl", "@type": "@id" }, 21 | 22 | "subtitle": "bc:subtitle", 23 | 24 | "jobTitle": "schema:jobTitle", 25 | 26 | "creator": { "@id": "dc:creator", "@type": "@id" }, 27 | "expires": { 28 | "@id": "sec:expiration", 29 | "@type": "xsd:dateTime" 30 | }, 31 | "revoked": { 32 | "@id": "sec:expiration", 33 | "@type": "xsd:dateTime" 34 | }, 35 | "CryptographicKey": "sec:Key", 36 | "signature": "sec:signature", 37 | 38 | "verification": "bc:verification", 39 | "publicKeys": "bc:publicKeys", 40 | 41 | "ChainpointSHA256v2": "cp:ChainpointSHA256v2", 42 | "BTCOpReturn": "cp:BTCOpReturn", 43 | "targetHash": "cp:targetHash", 44 | "merkleRoot": "cp:merkleRoot", 45 | "proof": "cp:proof", 46 | "anchors": "cp:anchors", 47 | "sourceId": "cp:sourceId", 48 | "right": "cp:right", 49 | "left": "cp:left" 50 | }, 51 | "obi:validation": [ 52 | { 53 | "obi:validatesType": "RecipientProfile", 54 | "obi:validationSchema": "https://w3id.org/blockcerts/schema/2.0-alpha/recipientSchema.json" 55 | }, 56 | { 57 | "obi:validatesType": "SignatureLine", 58 | "obi:validationSchema": "https://w3id.org/blockcerts/schema/2.0-alpha/signatureLineSchema.json" 59 | }, 60 | { 61 | "obi:validatesType": "MerkleProof2017", 62 | "obi:validationSchema": "https://w3id.org/blockcerts/schema/2.0-alpha/merkleProof2017Schema.json" 63 | } 64 | ] 65 | } 66 | -------------------------------------------------------------------------------- /cert_schema/2.0-alpha/issuerSchema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "$id": "https://w3id.org/blockcerts/schema/2.0-alpha/issuerSchema.json", 4 | "title": "IssuerProfile schema", 5 | "description": "Blockcerts 2.0 Issuer Identification (Profile) schema. Extends https://w3id.org/openbadges#Profile, a type that is embedded in an Open Badge and/or hosted at an issuer URI. Blockcerts specializes the Issuer Profile type into 2 schemas: the core that is embedded in the certificate (which matches the Open Badges Profile type), and one that is to be hosted at an issuer URI, to support blockchain verification of claims. This schema describes the latter. The issuer-hosted Profile is used in the Blockcerts verification process to look up the current list of public keys claimed by the issuer. This also defines an `introductionURL` which may be used by recipients (or software agents) to submit an introduction to the issuer. ", 6 | "type": "object", 7 | "definitions": { 8 | "JsonLdContext": { 9 | "description": "A link to a valid JSON-LD context, or array of JSON-LD contexts", 10 | "oneOf": [ 11 | { 12 | "type": "string" 13 | }, 14 | { 15 | "type": "array", 16 | "items": { 17 | "oneOf": [ 18 | { 19 | "type": "string" 20 | }, 21 | { 22 | "type": "object" 23 | }, 24 | { 25 | "type": "array" 26 | } 27 | ] 28 | } 29 | } 30 | ] 31 | }, 32 | "JsonLdType": { 33 | "description": "A type or an array of types defined in a referenced JSON-LD context.", 34 | "oneOf": [ 35 | { 36 | "type": "string" 37 | }, 38 | { 39 | "type": "array", 40 | "items": { 41 | "type": "string" 42 | } 43 | } 44 | ] 45 | }, 46 | "ImageUri": { 47 | "description": "An image representative of the entity. In Blockcerts this is typically a data URI embedded as a base-64 encoded PNG image, but it may also be a URI where the image may be found.", 48 | "type": "string", 49 | "anyOf": [ 50 | { 51 | "type": "string", 52 | "pattern": "^data:" 53 | }, 54 | { 55 | "type": "string", 56 | "format": "uri" 57 | } 58 | ] 59 | }, 60 | "ISODateTime": { 61 | "description": "ISO 8601 date format string `yyyy-MM-dd'T'HH:mm:ss.SSS` with optional `.SSS` milliseconds", 62 | "type": "string" 63 | }, 64 | "UNIXTimeStamp": { 65 | "description": "10-digit UNIX timestamp, epoch time", 66 | "type": "integer", 67 | "minimum": 0, 68 | "maximum": 9999999999 69 | }, 70 | "DateTime": { 71 | "anyOf": [ 72 | { 73 | "$ref": "#/definitions/ISODateTime" 74 | }, 75 | { 76 | "$ref": "#/definitions/UNIXTimeStamp" 77 | } 78 | ] 79 | }, 80 | "CryptographicKey": { 81 | "description": "Defined by https://web-payments.org/vocabs/security#Key", 82 | "type": "object", 83 | "properties": { 84 | "publicKey": { 85 | "type": "string", 86 | "pattern": "^ecdsa-koblitz-pubkey:", 87 | "description": "Issuer public key or blockchain address IRI with `:` prefix. For Bitcoin transactions, this would be the issuer public address prefixed with `ecdsa-koblitz-pubkey:`; e.g. `ecdsa-koblitz-pubkey:14RZvYazz9H2DC2skBfpPVxax54g4yabxe`" 88 | }, 89 | "created": { 90 | "$ref": "#/definitions/DateTime" 91 | }, 92 | "expires": { 93 | "$ref": "#/definitions/DateTime" 94 | }, 95 | "revoked": { 96 | "$ref": "#/definitions/DateTime" 97 | } 98 | }, 99 | "required": [ 100 | "publicKey", 101 | "created" 102 | ] 103 | }, 104 | "Profile": { 105 | "$id": "#profile", 106 | "description": "Defined by https://w3id.org/openbadges#Profile. This type is used in certificates, and in the issuer-hosted identification page. The minimal set of properties required in the certificate are `id` and `type`. In this case, additional issuer-identification properties are assumed to be available at the issuer-hosted identification page.", 107 | "properties": { 108 | "id": { 109 | "type": "string", 110 | "format": "uri", 111 | "description": "Defined by `id` property of https://w3id.org/openbadges#Profile" 112 | }, 113 | "type": { 114 | "$ref": "#/definitions/JsonLdType", 115 | "description": "Defined by `type` property of https://w3id.org/openbadges#Profile" 116 | }, 117 | "name": { 118 | "type": "string", 119 | "description": "Defined by `name` property of https://w3id.org/openbadges#Profile" 120 | }, 121 | "url": { 122 | "type": "string", 123 | "format": "uri", 124 | "description": "Defined by `url` property of https://w3id.org/openbadges#Profile" 125 | }, 126 | "telephone": { 127 | "type": "string", 128 | "description": "Defined by `telephone` property of https://w3id.org/openbadges#Profile" 129 | }, 130 | "description": { 131 | "type": "string", 132 | "description": "Defined by `description` property of https://w3id.org/openbadges#Profile" 133 | }, 134 | "image": { 135 | "$ref": "#/definitions/ImageUri", 136 | "description": "Defined by `image` property of https://w3id.org/openbadges#Profile" 137 | }, 138 | "email": { 139 | "type": "string", 140 | "description": "Defined by `email` property of https://w3id.org/openbadges#Profile" 141 | }, 142 | "revocationList": { 143 | "anyOf": [ 144 | { 145 | "type": "string", 146 | "format": "uri" 147 | }, 148 | { 149 | "type": "null" 150 | } 151 | ], 152 | "description": "Defined by `revocationList` property of https://w3id.org/openbadges#Profile. If embedded in a Blockcert and the issuer-hosted Profile, the value in the Blockcert should take preference." 153 | } 154 | }, 155 | "required": [ 156 | "id", 157 | "type" 158 | ] 159 | } 160 | }, 161 | "allOf": [ 162 | { 163 | "$ref": "#/definitions/Profile" 164 | } 165 | ], 166 | "properties": { 167 | "publicKeys": { 168 | "type": "array", 169 | "description": "Array of CryptographicKey (https://web-payments.org/vocabs/security#Key) references or objects. Entries may be dereferencable URIs of a document describing a CryptographicKey, or an embedded description of a CryptographicKey.", 170 | "items": { 171 | "anyOf": [ 172 | { 173 | "type": "string", 174 | "format": "uri", 175 | "description": "Cryptographic key URI" 176 | }, 177 | { 178 | "$ref": "#/definitions/CryptographicKey" 179 | } 180 | ] 181 | } 182 | }, 183 | "introductionURL": { 184 | "type": "string", 185 | "format": "uri", 186 | "description": "Blockcerts extension: URI where potential recipients (or their agents) should submit introductions, including recipient public key. If the issuer supports certificate wallet introductions, this field should specify the endpoint for use by certificate wallets. Otherwise, it can represent a URI enabling some other form of introduction; for example an HTTP IRI for a web form that to be filled out by the recipient." 187 | } 188 | }, 189 | "required": [ 190 | "id", 191 | "type", 192 | "name", 193 | "url", 194 | "publicKeys" 195 | ] 196 | } 197 | -------------------------------------------------------------------------------- /cert_schema/2.0-alpha/merkleProof2017Schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "MerkleProof2017 schema", 4 | "description": "An extension that allows an issuer to issue an Open Badge on the blockchain and provide proof of inclusion in a blockchain transaction. This uses the Chainpoint v2.0 specification: https://chainpoint.org/", 5 | "type": "object", 6 | "definitions": { 7 | "JsonLdType": { 8 | "description": "A type or an array of types defined in a JSON-LD context file.", 9 | "oneOf": [ 10 | { 11 | "type": "string" 12 | }, 13 | { 14 | "type": "array", 15 | "items": { 16 | "type": "string" 17 | } 18 | } 19 | ] 20 | } 21 | }, 22 | "properties": { 23 | "type": { 24 | "$ref": "#/definitions/JsonLdType" 25 | }, 26 | "merkleRoot": { 27 | "type": "string" 28 | }, 29 | "targetHash": { 30 | "type": "string" 31 | }, 32 | "proof": { 33 | "type": "array", 34 | "items": { 35 | "type": "object", 36 | "properties": { 37 | "right": { 38 | "type": "string" 39 | }, 40 | "left": { 41 | "type": "string" 42 | } 43 | } 44 | } 45 | }, 46 | "anchors": { 47 | "type": "array", 48 | "items": { 49 | "type": "object", 50 | "properties": { 51 | "sourceId": { 52 | "type": "string" 53 | }, 54 | "type": { 55 | "type": "string" 56 | } 57 | } 58 | } 59 | } 60 | }, 61 | "required": ["type", "merkleRoot", "targetHash", "proof", "anchors"] 62 | } 63 | -------------------------------------------------------------------------------- /cert_schema/2.0-alpha/recipientSchema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "RecipientProfile schema", 4 | "description": "A Blockcerts extension allowing inclusion of additional recipient details, including recipient publicKey and name. Inclusion of the recipient publicKey allows the recipient to make a strong claim of ownership over the key, and hence the badge being awarded. In the future, publicKey will be deprecated in favor of a decentralized id (DID) in the `id` field.", 5 | "type": "object", 6 | "properties": { 7 | "id": { 8 | "type": "string", 9 | "description": "reserved for future use as DID" 10 | }, 11 | "name": { 12 | "type": "string", 13 | "description": "Name of recipient, http://schema.org/name" 14 | }, 15 | "publicKey": { 16 | "type": "string", 17 | "format": "uri", 18 | "description": "In Blockcerts `publicKey` IRIs are typically represented with a `:` prefix. For Bitcoin transactions, this would be the recipient public Bitcoin address prefixed with `ecdsa-koblitz-pubkey:`; e.g. `ecdsa-koblitz-pubkey:14RZvYazz9H2DC2skBfpPVxax54g4yabxe`" 19 | } 20 | } 21 | } 22 | 23 | 24 | -------------------------------------------------------------------------------- /cert_schema/2.0-alpha/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "Assertion schema", 4 | "description": "Blockcerts 2.0 Assertion schema. Extends Open Badges v2.0 schema: https://w3id.org/openbadges#Assertion", 5 | "type": "object", 6 | "definitions": { 7 | "JsonLdContext": { 8 | "description": "A link to a valid JSON-LD context, or array of JSON-LD contexts", 9 | "oneOf": [ 10 | { 11 | "type": "string" 12 | }, 13 | { 14 | "type": "array", 15 | "items": { 16 | "oneOf": [ 17 | { 18 | "type": "string" 19 | }, 20 | { 21 | "type": "object" 22 | }, 23 | { 24 | "type": "array" 25 | } 26 | ] 27 | } 28 | } 29 | ] 30 | }, 31 | "JsonLdType": { 32 | "description": "A type or an array of types defined in a referenced JSON-LD context.", 33 | "oneOf": [ 34 | { 35 | "type": "string" 36 | }, 37 | { 38 | "type": "array", 39 | "items": { 40 | "type": "string" 41 | } 42 | } 43 | ] 44 | }, 45 | "ISODateTime": { 46 | "description": "ISO 8601 date format string `yyyy-MM-dd'T'HH:mm:ss.SSS` with optional `.SSS` milliseconds", 47 | "type": "string" 48 | }, 49 | "UNIXTimeStamp": { 50 | "description": "10-digit UNIX timestamp, epoch time", 51 | "type": "integer", 52 | "minimum": 0, 53 | "maximum": 9999999999 54 | }, 55 | "DateTime": { 56 | "anyOf": [ 57 | { 58 | "$ref": "#/definitions/ISODateTime" 59 | }, 60 | { 61 | "$ref": "#/definitions/UNIXTimeStamp" 62 | } 63 | ] 64 | }, 65 | "HashString": { 66 | "type": "string", 67 | "description": "Open Badges SHA-256 Hash", 68 | "pattern": "^sha256\\$[a-fA-F0-9]{64}$" 69 | 70 | }, 71 | "IdentityObject": { 72 | "title": "Badge Identity Object", 73 | "description": "From https://w3id.org/openbadges#IdentityObject, with extensions for recipient profile.", 74 | "type": "object", 75 | "properties": { 76 | "identity": { 77 | "description": "Defined by `identity` property of https://w3id.org/openbadges#IdentityObject", 78 | "oneOf": [ 79 | { 80 | "$ref": "#/definitions/HashString" 81 | }, 82 | { 83 | "type": "string", 84 | "format": "email" 85 | } 86 | ] 87 | }, 88 | "type": { 89 | "type": "string", 90 | "enum": [ 91 | "email" 92 | ], 93 | "description": "Defined by `type` property of https://w3id.org/openbadges#IdentityObject" 94 | }, 95 | "hashed": { 96 | "type": "boolean", 97 | "description": "Defined by `hashed` property of https://w3id.org/openbadges#IdentityObject" 98 | }, 99 | "salt": { 100 | "description": "Defined by `salt` property of https://w3id.org/openbadges#IdentityObject", 101 | "anyOf": [ 102 | { 103 | "type": "string" 104 | }, 105 | { 106 | "type": "null" 107 | } 108 | ] 109 | }, 110 | "recipientProfile": { 111 | "$ref": "https://w3id.org/blockcerts/schema/2.0-alpha/recipientSchema.json" 112 | } 113 | }, 114 | "required": [ 115 | "identity", 116 | "type", 117 | "hashed" 118 | ] 119 | }, 120 | "VerificationObject": { 121 | "description": "From https://w3id.org/openbadges#VerificationObject, with extensions for Blockcerts verification", 122 | "type": "object", 123 | "properties": { 124 | "type": { 125 | "$ref": "#/definitions/JsonLdType", 126 | "description": "Defined by `type` property of https://w3id.org/openbadges#VerificationObject. Blockcerts extension: this should contain the entry `MerkleProofVerification2017`" 127 | }, 128 | "creator": { 129 | "type": "string", 130 | "anyOf": [{ 131 | "type": "string", 132 | "pattern": "^ecdsa-koblitz-pubkey:", 133 | "description": "Issuer public key or blockchain address with `:` prefix. For Bitcoin transactions, this would be the issuer public address prefixed with `ecdsa-koblitz-pubkey:`. Example: `ecdsa-koblitz-pubkey:14RZvYazz9H2DC2skBfpPVxax54g4yabxe`" 134 | }, { 135 | "type": "string", 136 | "format": "uri" 137 | } 138 | ], 139 | "description": "Blockcerts extension: the expected blockchain address for the signer of the transaction containing the merkle proof. In Blockcerts `creator` IRIs are typically represented with a `:` prefix. For Bitcoin transactions, this would be the issuer public Bitcoin address prefixed with `ecdsa-koblitz-pubkey:`; e.g. `ecdsa-koblitz-pubkey:14RZvYazz9H2DC2skBfpPVxax54g4yabxe`" 140 | }, 141 | "verificationProperty": { 142 | "type": "object", 143 | "description": "Defined by `verificationProperty` property of https://w3id.org/openbadges#VerificationObject" 144 | }, 145 | "startsWith": { 146 | "type": "string", 147 | "format": "uri", 148 | "description": "Defined by `startsWith` property of https://w3id.org/openbadges#VerificationObject" 149 | }, 150 | "allowedOrigins": { 151 | "type": "string", 152 | "format": "uri", 153 | "description": "Defined by `allowedOrigins` property of https://w3id.org/openbadges#VerificationObject" 154 | } 155 | }, 156 | "required": [ 157 | "type" 158 | ] 159 | }, 160 | "ImageUri": { 161 | "description": "An image representative of the entity. In Blockcerts this is typically a data URI (https://en.wikipedia.org/wiki/Data_URI_scheme) embedded as a base-64 encoded PNG image, but it may also be a URI where the image may be found.", 162 | "type": "string", 163 | "anyOf": [ 164 | { 165 | "type": "string", 166 | "pattern": "^data:" 167 | }, 168 | { 169 | "type": "string", 170 | "format": "uri" 171 | } 172 | ] 173 | }, 174 | "AlignmentObject": { 175 | "description": "From https://w3id.org/openbadges#AlignmentObject", 176 | "type": "object", 177 | "properties": { 178 | "targetName": { 179 | "type": "string", 180 | "description": "Defined by `targetName` property of https://w3id.org/openbadges#AlignmentObject" 181 | }, 182 | "targetUrl": { 183 | "type": "string", 184 | "format": "uri", 185 | "description": "Defined by `targetUrl` property of https://w3id.org/openbadges#AlignmentObject" 186 | }, 187 | "targetDescription": { 188 | "type": "string", 189 | "description": "Defined by `targetDescription` property of https://w3id.org/openbadges#AlignmentObject" 190 | } 191 | }, 192 | "required": [ 193 | "targetName", 194 | "targetUrl" 195 | ] 196 | }, 197 | "AlignmentArray": { 198 | "description": "List of objects describing which objectives or educational standards this badge aligns to, if any.", 199 | "type": "array", 200 | "items": { 201 | "$ref": "#/definitions/AlignmentObject" 202 | } 203 | }, 204 | "TagsArray": { 205 | "description": "List of tags that describe the type of achievement.", 206 | "type": "array", 207 | "items": { 208 | "type": "string" 209 | }, 210 | "uniqueItems": true 211 | }, 212 | "SignatureLine": { 213 | "$ref": "https://w3id.org/blockcerts/schema/2.0-alpha/signatureLineSchema.json" 214 | }, 215 | "MerkleProof2017": { 216 | "$ref": "https://w3id.org/blockcerts/schema/2.0-alpha/merkleProof2017Schema.json" 217 | }, 218 | "BadgeClass": { 219 | "description": "From https://w3id.org/openbadges#BadgeClass", 220 | "type": "object", 221 | "properties": { 222 | "id": { 223 | "type": "string", 224 | "format": "uri", 225 | "description": "Defined by `id` property of https://w3id.org/openbadges#BadgeClass. This field is required in Open Badges but currently optional in Blockcerts for compatibility. This may be an HTTP IRI, but only if the issuer plans to host the BadgeClass definitions on a long-term basis, or (at least) until expiration of certificates referencing this BadgeClass. Otherwise it is recommended to use a `urn:uuid:`-formatted IRI." 226 | }, 227 | "type": { 228 | "$ref": "#/definitions/JsonLdType", 229 | "description": "Defined by `type` property of https://w3id.org/openbadges#BadgeClass" 230 | }, 231 | "name": { 232 | "type": "string", 233 | "description": "Defined by `name` property of https://w3id.org/openbadges#BadgeClass" 234 | }, 235 | "subtitle": { 236 | "type": "string", 237 | "description": "Blockcerts extension: optional subtitle of the certificate" 238 | }, 239 | "description": { 240 | "type": "string", 241 | "description": "Defined by `description` property of https://w3id.org/openbadges#BadgeClass" 242 | }, 243 | "image": { 244 | "$ref": "#/definitions/ImageUri", 245 | "description": "Defined by `image` property of https://w3id.org/openbadges#BadgeClass" 246 | }, 247 | "criteria": { 248 | "type": "object", 249 | "description": "Defined by `criteria` property of https://w3id.org/openbadges#BadgeClass. This field is required in Open Badges, currently optional in Blockcerts for compatibility. " 250 | }, 251 | "issuer": { 252 | "$ref": "#/definitions/Profile", 253 | "description": "Defined by `issuer` property of https://w3id.org/openbadges#BadgeClass, with Blockcerts extensions for blockchain verification of badges." 254 | }, 255 | "alignment": { 256 | "$ref": "#/definitions/AlignmentArray", 257 | "description": "Defined by `alignment` property of https://w3id.org/openbadges#BadgeClass" 258 | }, 259 | "tags": { 260 | "$ref": "#/definitions/TagsArray", 261 | "description": "Defined by `tags` property of https://w3id.org/openbadges#BadgeClass" 262 | }, 263 | "signatureLines": { 264 | "anyOf": [ 265 | { 266 | "$ref": "#/definitions/SignatureLine" 267 | }, 268 | { 269 | "type": "array", 270 | "items": { 271 | "$ref": "#/definitions/SignatureLine" 272 | } 273 | } 274 | ], 275 | "description": "Blockcerts extension: array of signature lines for display." 276 | } 277 | }, 278 | "required": [ 279 | "name", 280 | "description", 281 | "image", 282 | "issuer" 283 | ] 284 | }, 285 | "Profile": { 286 | "description": "Defined by https://w3id.org/openbadges#Profile. This type is used in certificates, and in the issuer-hosted identification page. The minimal set of properties required in the certificate are `id` and `type`. In this case, additional issuer-identification properties are assumed to be available at the issuer-hosted identification page.", 287 | "properties": { 288 | "id": { 289 | "type": "string", 290 | "format": "uri", 291 | "description": "Defined by `id` property of https://w3id.org/openbadges#Profile" 292 | }, 293 | "type": { 294 | "$ref": "#/definitions/JsonLdType", 295 | "description": "Defined by `type` property of https://w3id.org/openbadges#Profile" 296 | }, 297 | "name": { 298 | "type": "string", 299 | "description": "Defined by `name` property of https://w3id.org/openbadges#Profile" 300 | }, 301 | "url": { 302 | "type": "string", 303 | "format": "uri", 304 | "description": "Defined by `url` property of https://w3id.org/openbadges#Profile" 305 | }, 306 | "telephone": { 307 | "type": "string", 308 | "description": "Defined by `telephone` property of https://w3id.org/openbadges#Profile" 309 | }, 310 | "description": { 311 | "type": "string", 312 | "description": "Defined by `description` property of https://w3id.org/openbadges#Profile" 313 | }, 314 | "image": { 315 | "$ref": "#/definitions/ImageUri", 316 | "description": "Defined by `image` property of https://w3id.org/openbadges#Profile" 317 | }, 318 | "email": { 319 | "type": "string", 320 | "description": "Defined by `email` property of https://w3id.org/openbadges#Profile" 321 | }, 322 | "revocationList": { 323 | "anyOf": [ 324 | { 325 | "type": "string", 326 | "format": "uri" 327 | }, 328 | { 329 | "type": "null" 330 | } 331 | ], 332 | "description": "Defined by `revocationList` property of https://w3id.org/openbadges#Profile. If embedded in a Blockcert and the issuer-hosted Profile, the value in the Blockcert should take preference." 333 | } 334 | }, 335 | "required": [ 336 | "id", 337 | "type" 338 | ] 339 | } 340 | }, 341 | "properties": { 342 | "id": { 343 | "description": "Defined by `id` property in https://w3id.org/openbadges#Assertion. This may be an HTTP IRI, but only if the issuer plans to host the assertions on a long-term basis, or (at least) until their expiration. Otherwise it is recommended to use a `urn:uuid:`-formatted IRI.", 344 | "type": "string", 345 | "anyOf": [ 346 | { 347 | "type": "string", 348 | "pattern": "^urn:uuid:" 349 | }, 350 | { 351 | "type": "string", 352 | "format": "uri" 353 | } 354 | ] 355 | }, 356 | "type": { 357 | "$ref": "#/definitions/JsonLdType", 358 | "description": "Defined by `type` property of https://w3id.org/openbadges#Assertion" 359 | }, 360 | "recipient": { 361 | "$ref": "#/definitions/IdentityObject", 362 | "description": "Defined by `recipient` property of https://w3id.org/openbadges#Assertion, with Blockcerts extensions for recipient proof of ownership." 363 | }, 364 | "badge": { 365 | "$ref": "#/definitions/BadgeClass", 366 | "description": "Defined by `badge` property of https://w3id.org/openbadges#Assertion, with Blockcerts extensions for (display) signature images." 367 | }, 368 | "verification": { 369 | "$ref": "#/definitions/VerificationObject", 370 | "description": "Defined by `verification` property of https://w3id.org/openbadges#Assertion, with Blockcerts extensions for verification of badges on a blockchain." 371 | }, 372 | "issuedOn": { 373 | "$ref": "#/definitions/DateTime", 374 | "description": "Defined by `issuedOn` property of https://w3id.org/openbadges#Assertion" 375 | }, 376 | "image": { 377 | "$ref": "#/definitions/ImageUri", 378 | "description": "Defined by `image` property of https://w3id.org/openbadges#Assertion" 379 | }, 380 | "evidence": { 381 | "type": "string", 382 | "format": "uri", 383 | "description": "Defined by `evidence` property of https://w3id.org/openbadges#Assertion" 384 | }, 385 | "narrative": { 386 | "type": "string", 387 | "description": "Defined by `narrative` property of https://w3id.org/openbadges#Assertion" 388 | }, 389 | "expires": { 390 | "$ref": "#/definitions/DateTime", 391 | "description": "Defined by `expires` property of https://w3id.org/openbadges#Assertion" 392 | }, 393 | "signature": { 394 | "ref": "#/definitions/MerkleProof2017" 395 | } 396 | }, 397 | "required": [ 398 | "id", 399 | "type", 400 | "recipient", 401 | "badge", 402 | "verification", 403 | "issuedOn" 404 | ], 405 | "additionalProperties": true 406 | } 407 | -------------------------------------------------------------------------------- /cert_schema/2.0-alpha/signatureLineSchema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "SignatureLine schema", 4 | "description": "An extension that allows issuers to add signature lines to the visual representation of the badge. This is not part of the cryptographic proof; it is for display purposes only.", 5 | "type": "object", 6 | "definitions": { 7 | "ImageUri": { 8 | "anyOf": [ 9 | { 10 | "type": "string", 11 | "pattern": "data:image/png;base64,", 12 | "description": "An image representative of the entity. In Blockcerts this is typically a data URI (https://en.wikipedia.org/wiki/Data_URI_scheme) embedded as a base-64 encoded PNG image, but it may also be a URI where the image may be found." 13 | }, 14 | { 15 | "type": "string", 16 | "format": "uri", 17 | "description": "IRI (typically HTTP) representing this signature image." 18 | } 19 | ] 20 | } 21 | }, 22 | "properties": { 23 | "image": { 24 | "$ref": "#/definitions/ImageUri" 25 | }, 26 | "jobTitle": { 27 | "type": "string", 28 | "description": "Job title of signer, http://schema.org/jobTitle" 29 | }, 30 | "name": { 31 | "type": "string", 32 | "description": "Full name of signer, http://schema.org/name" 33 | } 34 | }, 35 | "required": ["image"] 36 | } 37 | -------------------------------------------------------------------------------- /cert_schema/2.0/context.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": { 3 | "id": "@id", 4 | "type": "@type", 5 | "bc": "https://w3id.org/blockcerts#", 6 | "obi": "https://w3id.org/openbadges#", 7 | "cp": "https://w3id.org/chainpoint#", 8 | "schema": "http://schema.org/", 9 | "sec": "https://w3id.org/security#", 10 | "xsd": "http://www.w3.org/2001/XMLSchema#", 11 | 12 | "MerkleProof2017": "sec:MerkleProof2017", 13 | 14 | "RecipientProfile": "bc:RecipientProfile", 15 | "SignatureLine": "bc:SignatureLine", 16 | "MerkleProofVerification2017": "bc:MerkleProofVerification2017", 17 | 18 | "recipientProfile": "bc:recipientProfile", 19 | "signatureLines": "bc:signatureLines", 20 | "introductionUrl": { "@id": "bc:introductionUrl", "@type": "@id" }, 21 | 22 | "subtitle": "bc:subtitle", 23 | 24 | "jobTitle": "schema:jobTitle", 25 | 26 | "expires": { 27 | "@id": "sec:expiration", 28 | "@type": "xsd:dateTime" 29 | }, 30 | "revoked": { 31 | "@id": "obi:revoked", 32 | "@type": "xsd:boolean" 33 | }, 34 | "CryptographicKey": "sec:Key", 35 | "signature": "sec:signature", 36 | "verification": { 37 | "@id": "obi:verify", 38 | "@type": "@id" 39 | }, 40 | "publicKey": { 41 | "@id": "sec:publicKey", 42 | "@type": "@id" 43 | }, 44 | 45 | "BTCOpReturn": "cp:BTCOpReturn", 46 | "targetHash": "cp:targetHash", 47 | "merkleRoot": "cp:merkleRoot", 48 | "proof": "cp:proof", 49 | "anchors": "cp:anchors", 50 | "sourceId": "cp:sourceId", 51 | "right": "cp:right", 52 | "left": "cp:left" 53 | }, 54 | "obi:validation": [ 55 | { 56 | "obi:validatesType": "RecipientProfile", 57 | "obi:validationSchema": "https://w3id.org/blockcerts/schema/2.0/recipientSchema.json" 58 | }, 59 | { 60 | "obi:validatesType": "SignatureLine", 61 | "obi:validationSchema": "https://w3id.org/blockcerts/schema/2.0/signatureLineSchema.json" 62 | }, 63 | { 64 | "obi:validatesType": "MerkleProof2017", 65 | "obi:validationSchema": "https://w3id.org/blockcerts/schema/2.0/merkleProof2017Schema.json" 66 | } 67 | ] 68 | } 69 | -------------------------------------------------------------------------------- /cert_schema/2.0/issuerSchema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "IssuerProfile schema", 4 | "description": "Blockcerts 2.0 Issuer Identification (Profile) schema. Extends https://w3id.org/openbadges#Profile, a type that is embedded in an Open Badge and/or hosted at an issuer URI. Blockcerts specializes the Issuer Profile type into 2 schemas: the core that is embedded in the certificate (which matches the Open Badges Profile type), and one that is to be hosted at an issuer URI, to support blockchain verification of claims. This schema describes the latter. The issuer-hosted Profile is used in the Blockcerts verification process to look up the current list of public keys claimed by the issuer. This also defines an `introductionURL` which may be used by recipients (or software agents) to submit an introduction to the issuer. ", 5 | "type": "object", 6 | "definitions": { 7 | "JsonLdContext": { 8 | "description": "A link to a valid JSON-LD context, or array of JSON-LD contexts", 9 | "oneOf": [ 10 | { 11 | "type": "string" 12 | }, 13 | { 14 | "type": "array", 15 | "items": { 16 | "oneOf": [ 17 | { 18 | "type": "string" 19 | }, 20 | { 21 | "type": "object" 22 | }, 23 | { 24 | "type": "array" 25 | } 26 | ] 27 | } 28 | } 29 | ] 30 | }, 31 | "JsonLdType": { 32 | "description": "A type or an array of types defined in a referenced JSON-LD context.", 33 | "oneOf": [ 34 | { 35 | "type": "string" 36 | }, 37 | { 38 | "type": "array", 39 | "items": { 40 | "type": "string" 41 | } 42 | } 43 | ] 44 | }, 45 | "ImageUri": { 46 | "description": "An image representative of the entity. In Blockcerts this is typically a data URI embedded as a base-64 encoded PNG image, but it may also be a URI where the image may be found.", 47 | "type": "string", 48 | "anyOf": [ 49 | { 50 | "type": "string", 51 | "pattern": "^data:" 52 | }, 53 | { 54 | "type": "string", 55 | "format": "uri" 56 | } 57 | ] 58 | }, 59 | "DateTime": { 60 | "description": "ISO 8601 datetime", 61 | "type": "string" 62 | }, 63 | "CryptographicKey": { 64 | "description": "Defined by https://web-payments.org/vocabs/security#Key", 65 | "type": "object", 66 | "properties": { 67 | "id": { 68 | "type": "string", 69 | "pattern": "^ecdsa-koblitz-pubkey:", 70 | "description": "Issuer public key or blockchain address IRI with `:` prefix. For Bitcoin transactions, this would be the issuer public address prefixed with `ecdsa-koblitz-pubkey:`; e.g. `ecdsa-koblitz-pubkey:14RZvYazz9H2DC2skBfpPVxax54g4yabxe`" 71 | }, 72 | "created": { 73 | "$ref": "#/definitions/DateTime" 74 | }, 75 | "expires": { 76 | "$ref": "#/definitions/DateTime" 77 | }, 78 | "revoked": { 79 | "$ref": "#/definitions/DateTime" 80 | } 81 | }, 82 | "required": [ 83 | "id", 84 | "created" 85 | ] 86 | }, 87 | "Profile": { 88 | "$id": "#profile", 89 | "description": "Defined by https://w3id.org/openbadges#Profile. This type is used in certificates, and in the issuer-hosted identification page. The minimal set of properties required in the certificate are `id` and `type`. In this case, additional issuer-identification properties are assumed to be available at the issuer-hosted identification page.", 90 | "properties": { 91 | "id": { 92 | "type": "string", 93 | "format": "uri", 94 | "description": "Defined by `id` property of https://w3id.org/openbadges#Profile" 95 | }, 96 | "type": { 97 | "$ref": "#/definitions/JsonLdType", 98 | "description": "Defined by `type` property of https://w3id.org/openbadges#Profile" 99 | }, 100 | "name": { 101 | "type": "string", 102 | "description": "Defined by `name` property of https://w3id.org/openbadges#Profile" 103 | }, 104 | "url": { 105 | "type": "string", 106 | "format": "uri", 107 | "description": "Defined by `url` property of https://w3id.org/openbadges#Profile" 108 | }, 109 | "telephone": { 110 | "type": "string", 111 | "description": "Defined by `telephone` property of https://w3id.org/openbadges#Profile" 112 | }, 113 | "description": { 114 | "type": "string", 115 | "description": "Defined by `description` property of https://w3id.org/openbadges#Profile" 116 | }, 117 | "image": { 118 | "$ref": "#/definitions/ImageUri", 119 | "description": "Defined by `image` property of https://w3id.org/openbadges#Profile" 120 | }, 121 | "email": { 122 | "type": "string", 123 | "description": "Defined by `email` property of https://w3id.org/openbadges#Profile" 124 | }, 125 | "revocationList": { 126 | "anyOf": [ 127 | { 128 | "type": "string", 129 | "format": "uri" 130 | }, 131 | { 132 | "type": "null" 133 | } 134 | ], 135 | "description": "Defined by `revocationList` property of https://w3id.org/openbadges#Profile. If embedded in a Blockcert and the issuer-hosted Profile, the value in the Blockcert should take preference." 136 | } 137 | }, 138 | "required": [ 139 | "id", 140 | "type" 141 | ] 142 | } 143 | }, 144 | "allOf": [ 145 | { 146 | "$ref": "#/definitions/Profile" 147 | } 148 | ], 149 | "properties": { 150 | "publicKey": { 151 | "type": "array", 152 | "description": "Array of CryptographicKey (https://web-payments.org/vocabs/security#Key) references or objects. Entries may be dereferencable URIs of a document describing a CryptographicKey, or an embedded description of a CryptographicKey.", 153 | "items": { 154 | "anyOf": [ 155 | { 156 | "type": "string", 157 | "description": "Cryptographic key" 158 | }, 159 | { 160 | "$ref": "#/definitions/CryptographicKey" 161 | } 162 | ] 163 | } 164 | }, 165 | "introductionURL": { 166 | "type": "string", 167 | "format": "uri", 168 | "description": "Blockcerts extension: URI where potential recipients (or their agents) should submit introductions, including recipient public key. If the issuer supports certificate wallet introductions, this field should specify the endpoint for use by certificate wallets. Otherwise, it can represent a URI enabling some other form of introduction; for example an HTTP IRI for a web form that to be filled out by the recipient." 169 | } 170 | }, 171 | "required": [ 172 | "id", 173 | "type", 174 | "name", 175 | "url" 176 | ] 177 | } 178 | -------------------------------------------------------------------------------- /cert_schema/2.0/merkleProof2017Schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "MerkleProof2017 schema", 4 | "description": "An extension that allows an issuer to issue an Open Badge on the blockchain and provide proof of inclusion in a blockchain transaction.This uses the 2017 Merkle Proof Signature Suite (https://w3c-dvcg.github.io/lds-merkleproof2017/)", 5 | "type": "object", 6 | "definitions": { 7 | "JsonLdType": { 8 | "description": "A type or an array of types defined in a JSON-LD context file.", 9 | "oneOf": [ 10 | { 11 | "type": "string" 12 | }, 13 | { 14 | "type": "array", 15 | "items": { 16 | "type": "string" 17 | } 18 | } 19 | ] 20 | } 21 | }, 22 | "properties": { 23 | "type": { 24 | "$ref": "#/definitions/JsonLdType" 25 | }, 26 | "merkleRoot": { 27 | "type": "string" 28 | }, 29 | "targetHash": { 30 | "type": "string" 31 | }, 32 | "proof": { 33 | "type": "array", 34 | "items": { 35 | "type": "object", 36 | "properties": { 37 | "right": { 38 | "type": "string" 39 | }, 40 | "left": { 41 | "type": "string" 42 | } 43 | } 44 | } 45 | }, 46 | "anchors": { 47 | "type": "array", 48 | "items": { 49 | "type": "object", 50 | "properties": { 51 | "sourceId": { 52 | "type": "string" 53 | }, 54 | "type": { 55 | "type": "string" 56 | }, 57 | "chain": { 58 | "type": "string" 59 | } 60 | } 61 | } 62 | } 63 | }, 64 | "required": ["type", "merkleRoot", "targetHash", "proof", "anchors"] 65 | } 66 | -------------------------------------------------------------------------------- /cert_schema/2.0/obi.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": { 3 | "id": "@id", 4 | "type": "@type", 5 | "extensions": "https://w3id.org/openbadges/extensions#", 6 | "obi": "https://w3id.org/openbadges#", 7 | "validation": "obi:validation", 8 | "cred": "https://w3id.org/credentials#", 9 | "dc": "http://purl.org/dc/terms/", 10 | "schema": "http://schema.org/", 11 | "sec": "https://w3id.org/security#", 12 | "xsd": "http://www.w3.org/2001/XMLSchema#", 13 | "AlignmentObject": "schema:AlignmentObject", 14 | "CryptographicKey": "sec:Key", 15 | "Endorsement": "cred:Credential", 16 | "Assertion": "obi:Assertion", 17 | "BadgeClass": "obi:BadgeClass", 18 | "Criteria": "obi:Criteria", 19 | "Evidence": "obi:Evidence", 20 | "Extension": "obi:Extension", 21 | "FrameValidation": "obi:FrameValidation", 22 | "IdentityObject": "obi:IdentityObject", 23 | "Image": "obi:Image", 24 | "HostedBadge": "obi:HostedBadge", 25 | "hosted": "obi:HostedBadge", 26 | "Issuer": "obi:Issuer", 27 | "Profile": "obi:Profile", 28 | "RevocationList": "obi:RevocationList", 29 | "SignedBadge": "obi:SignedBadge", 30 | "signed": "obi:SignedBadge", 31 | "TypeValidation": "obi:TypeValidation", 32 | "VerificationObject": "obi:VerificationObject", 33 | "author": { 34 | "@id": "schema:author", 35 | "@type": "@id" 36 | }, 37 | "caption": { 38 | "@id": "schema:caption" 39 | }, 40 | "claim": { 41 | "@id": "cred:claim", 42 | "@type": "@id" 43 | }, 44 | "created": { 45 | "@id": "dc:created", 46 | "@type": "xsd:dateTime" 47 | }, 48 | "creator": { 49 | "@id": "dc:creator", 50 | "@type": "@id" 51 | }, 52 | "description": { 53 | "@id": "schema:description" 54 | }, 55 | "email": { 56 | "@id": "schema:email" 57 | }, 58 | "endorsement": { 59 | "@id": "cred:credential", 60 | "@type": "@id" 61 | }, 62 | "expires": { 63 | "@id": "sec:expiration", 64 | "@type": "xsd:dateTime" 65 | }, 66 | "genre": { 67 | "@id": "schema:genre" 68 | }, 69 | "image": { 70 | "@id": "schema:image", 71 | "@type": "@id" 72 | }, 73 | "name": { 74 | "@id": "schema:name" 75 | }, 76 | "owner": { 77 | "@id": "sec:owner", 78 | "@type": "@id" 79 | }, 80 | "publicKey": { 81 | "@id": "sec:publicKey", 82 | "@type": "@id" 83 | }, 84 | "publicKeyPem": { 85 | "@id": "sec:publicKeyPem" 86 | }, 87 | "related": { 88 | "@id": "dc:relation", 89 | "@type": "@id" 90 | }, 91 | "startsWith": { 92 | "@id": "http://purl.org/dqm-vocabulary/v1/dqm#startsWith" 93 | }, 94 | "tags": { 95 | "@id": "schema:keywords" 96 | }, 97 | "targetDescription": { 98 | "@id": "schema:targetDescription" 99 | }, 100 | "targetFramework": { 101 | "@id": "schema:targetFramework" 102 | }, 103 | "targetName": { 104 | "@id": "schema:targetName" 105 | }, 106 | "targetUrl": { 107 | "@id": "schema:targetUrl" 108 | }, 109 | "telephone": { 110 | "@id": "schema:telephone" 111 | }, 112 | "url": { 113 | "@id": "schema:url", 114 | "@type": "@id" 115 | }, 116 | "version": { 117 | "@id": "schema:version" 118 | }, 119 | "alignment": { 120 | "@id": "obi:alignment", 121 | "@type": "@id" 122 | }, 123 | "allowedOrigins": { 124 | "@id": "obi:allowedOrigins" 125 | }, 126 | "audience": { 127 | "@id": "obi:audience" 128 | }, 129 | "badge": { 130 | "@id": "obi:badge", 131 | "@type": "@id" 132 | }, 133 | "criteria": { 134 | "@id": "obi:criteria", 135 | "@type": "@id" 136 | }, 137 | "endorsementComment": { 138 | "@id": "obi:endorsementComment" 139 | }, 140 | "evidence": { 141 | "@id": "obi:evidence", 142 | "@type": "@id" 143 | }, 144 | "hashed": { 145 | "@id": "obi:hashed", 146 | "@type": "xsd:boolean" 147 | }, 148 | "identity": { 149 | "@id": "obi:identityHash" 150 | }, 151 | "issuedOn": { 152 | "@id": "obi:issueDate", 153 | "@type": "xsd:dateTime" 154 | }, 155 | "issuer": { 156 | "@id": "obi:issuer", 157 | "@type": "@id" 158 | }, 159 | "narrative": { 160 | "@id": "obi:narrative" 161 | }, 162 | "recipient": { 163 | "@id": "obi:recipient", 164 | "@type": "@id" 165 | }, 166 | "revocationList": { 167 | "@id": "obi:revocationList", 168 | "@type": "@id" 169 | }, 170 | "revocationReason": { 171 | "@id": "obi:revocationReason" 172 | }, 173 | "revoked": { 174 | "@id": "obi:revoked", 175 | "@type": "xsd:boolean" 176 | }, 177 | "revokedAssertions": { 178 | "@id": "obi:revoked" 179 | }, 180 | "salt": { 181 | "@id": "obi:salt" 182 | }, 183 | "targetCode": { 184 | "@id": "obi:targetCode" 185 | }, 186 | "uid": { 187 | "@id": "obi:uid" 188 | }, 189 | "validatesType": "obi:validatesType", 190 | "validationFrame": "obi:validationFrame", 191 | "validationSchema": "obi:validationSchema", 192 | "verification": { 193 | "@id": "obi:verify", 194 | "@type": "@id" 195 | }, 196 | "verificationProperty": { 197 | "@id": "obi:verificationProperty" 198 | }, 199 | "verify": "verification" 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /cert_schema/2.0/recipientSchema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "RecipientProfile schema", 4 | "description": "A Blockcerts extension allowing inclusion of additional recipient details, including recipient publicKey and name. Inclusion of the recipient publicKey allows the recipient to make a strong claim of ownership over the key, and hence the badge being awarded. In the future, publicKey will be deprecated in favor of a decentralized id (DID) in the `id` field.", 5 | "type": "object", 6 | "properties": { 7 | "id": { 8 | "type": "string", 9 | "description": "reserved for future use as DID" 10 | }, 11 | "name": { 12 | "type": "string", 13 | "description": "Name of recipient, http://schema.org/name" 14 | }, 15 | "publicKey": { 16 | "type": "string", 17 | "format": "uri", 18 | "description": "In Blockcerts `publicKey` IRIs are typically represented with a `:` prefix. For Bitcoin transactions, this would be the recipient public Bitcoin address prefixed with `ecdsa-koblitz-pubkey:`; e.g. `ecdsa-koblitz-pubkey:14RZvYazz9H2DC2skBfpPVxax54g4yabxe`" 19 | } 20 | } 21 | } 22 | 23 | 24 | -------------------------------------------------------------------------------- /cert_schema/2.0/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "Assertion schema", 4 | "description": "Blockcerts 2.0 Assertion schema. Extends Open Badges v2.0 schema: https://w3id.org/openbadges#Assertion", 5 | "type": "object", 6 | "definitions": { 7 | "JsonLdContext": { 8 | "description": "A link to a valid JSON-LD context, or array of JSON-LD contexts", 9 | "oneOf": [ 10 | { 11 | "type": "string" 12 | }, 13 | { 14 | "type": "array", 15 | "items": { 16 | "oneOf": [ 17 | { 18 | "type": "string" 19 | }, 20 | { 21 | "type": "object" 22 | }, 23 | { 24 | "type": "array" 25 | } 26 | ] 27 | } 28 | } 29 | ] 30 | }, 31 | "JsonLdType": { 32 | "description": "A type or an array of types defined in a referenced JSON-LD context.", 33 | "oneOf": [ 34 | { 35 | "type": "string" 36 | }, 37 | { 38 | "type": "array", 39 | "items": { 40 | "type": "string" 41 | } 42 | } 43 | ] 44 | }, 45 | "DateTime": { 46 | "description": "Open Badges must express timestamps as strings compatible with ISO 8601 guidelines, including the time and a time zone indicator. It is recommended to publish all timestamps in UTC. Previous versions of Open Badges allowed Unix timestamps as integers. Open Badges v2.0 requires string ISO 8601 values with time zone indicators. For example, 2016-12-31T23:59:59+00:00 is a valid ISO 8601 timestamp. It contains the year, month, day, T separator, hour number 0-23, minute, optional seconds and decimal microsecond, and a time zone indicator (+/- an offset from UTC or the Z designator for UTC).", 47 | "type": "string" 48 | }, 49 | "HashString": { 50 | "type": "string", 51 | "description": "Open Badges SHA-256 Hash", 52 | "pattern": "^sha256\\$[a-fA-F0-9]{64}$" 53 | 54 | }, 55 | "IdentityObject": { 56 | "title": "Badge Identity Object", 57 | "description": "From https://w3id.org/openbadges#IdentityObject.", 58 | "type": "object", 59 | "properties": { 60 | "identity": { 61 | "description": "Defined by `identity` property of https://w3id.org/openbadges#IdentityObject", 62 | "oneOf": [ 63 | { 64 | "$ref": "#/definitions/HashString" 65 | }, 66 | { 67 | "type": "string", 68 | "format": "email" 69 | } 70 | ] 71 | }, 72 | "type": { 73 | "type": "string", 74 | "enum": [ 75 | "email" 76 | ], 77 | "description": "Defined by `type` property of https://w3id.org/openbadges#IdentityObject" 78 | }, 79 | "hashed": { 80 | "type": "boolean", 81 | "description": "Defined by `hashed` property of https://w3id.org/openbadges#IdentityObject" 82 | }, 83 | "salt": { 84 | "description": "Defined by `salt` property of https://w3id.org/openbadges#IdentityObject", 85 | "anyOf": [ 86 | { 87 | "type": "string" 88 | }, 89 | { 90 | "type": "null" 91 | } 92 | ] 93 | } 94 | }, 95 | "required": [ 96 | "identity", 97 | "type", 98 | "hashed" 99 | ] 100 | }, 101 | "VerificationObject": { 102 | "description": "From https://w3id.org/openbadges#VerificationObject, with extensions for Blockcerts verification", 103 | "type": "object", 104 | "properties": { 105 | "type": { 106 | "$ref": "#/definitions/JsonLdType", 107 | "description": "Defined by `type` property of https://w3id.org/openbadges#VerificationObject. Blockcerts extension: this should contain the entry `MerkleProofVerification2017`" 108 | }, 109 | "publicKey": { 110 | "type": "string", 111 | "anyOf": [{ 112 | "type": "string", 113 | "pattern": "^ecdsa-koblitz-pubkey:", 114 | "description": "Issuer public key or blockchain address with `:` prefix. For Bitcoin transactions, this would be the issuer public address prefixed with `ecdsa-koblitz-pubkey:`. Example: `ecdsa-koblitz-pubkey:14RZvYazz9H2DC2skBfpPVxax54g4yabxe`" 115 | }, { 116 | "type": "string" 117 | } 118 | ], 119 | "description": "Blockcerts extension: the expected blockchain address for the signer of the transaction containing the merkle proof. In Blockcerts `publicKey`s are typically represented with a `:` prefix. For Bitcoin transactions, this would be the issuer public Bitcoin address prefixed with `ecdsa-koblitz-pubkey:`; e.g. `ecdsa-koblitz-pubkey:14RZvYazz9H2DC2skBfpPVxax54g4yabxe`" 120 | } 121 | }, 122 | "required": [ 123 | "type" 124 | ] 125 | }, 126 | "ImageUri": { 127 | "description": "An image representative of the entity. In Blockcerts this is typically a data URI (https://en.wikipedia.org/wiki/Data_URI_scheme) embedded as a base-64 encoded PNG image, but it may also be a URI where the image may be found.", 128 | "type": "string", 129 | "anyOf": [ 130 | { 131 | "type": "string", 132 | "pattern": "^data:" 133 | }, 134 | { 135 | "type": "string", 136 | "format": "uri" 137 | } 138 | ] 139 | }, 140 | "AlignmentObject": { 141 | "description": "From https://w3id.org/openbadges#AlignmentObject", 142 | "type": "object", 143 | "properties": { 144 | "targetName": { 145 | "type": "string", 146 | "description": "Defined by `targetName` property of https://w3id.org/openbadges#AlignmentObject" 147 | }, 148 | "targetUrl": { 149 | "type": "string", 150 | "format": "uri", 151 | "description": "Defined by `targetUrl` property of https://w3id.org/openbadges#AlignmentObject" 152 | }, 153 | "targetDescription": { 154 | "type": "string", 155 | "description": "Defined by `targetDescription` property of https://w3id.org/openbadges#AlignmentObject" 156 | } 157 | }, 158 | "required": [ 159 | "targetName", 160 | "targetUrl" 161 | ] 162 | }, 163 | "AlignmentArray": { 164 | "description": "List of objects describing which objectives or educational standards this badge aligns to, if any.", 165 | "type": "array", 166 | "items": { 167 | "$ref": "#/definitions/AlignmentObject" 168 | } 169 | }, 170 | "TagsArray": { 171 | "description": "List of tags that describe the type of achievement.", 172 | "type": "array", 173 | "items": { 174 | "type": "string" 175 | }, 176 | "uniqueItems": true 177 | }, 178 | "SignatureLine": { 179 | "$ref": "https://w3id.org/blockcerts/schema/2.0/signatureLineSchema.json" 180 | }, 181 | "RecipientProfile": { 182 | "$ref": "https://w3id.org/blockcerts/schema/2.0/recipientSchema.json" 183 | }, 184 | "MerkleProof2017": { 185 | "$ref": "https://w3id.org/blockcerts/schema/2.0/merkleProof2017Schema.json" 186 | }, 187 | "BadgeClass": { 188 | "description": "From https://w3id.org/openbadges#BadgeClass", 189 | "type": "object", 190 | "properties": { 191 | "id": { 192 | "type": "string", 193 | "format": "uri", 194 | "description": "Defined by `id` property of https://w3id.org/openbadges#BadgeClass. This field is now required in V2. This may be an HTTP IRI, but only if the issuer plans to host the BadgeClass definitions on a long-term basis, or (at least) until expiration of certificates referencing this BadgeClass. Otherwise it is recommended to use a `urn:uuid:`-formatted IRI." 195 | }, 196 | "type": { 197 | "$ref": "#/definitions/JsonLdType", 198 | "description": "Defined by `type` property of https://w3id.org/openbadges#BadgeClass" 199 | }, 200 | "name": { 201 | "type": "string", 202 | "description": "Defined by `name` property of https://w3id.org/openbadges#BadgeClass" 203 | }, 204 | "subtitle": { 205 | "type": "string", 206 | "description": "Blockcerts extension: optional subtitle of the certificate" 207 | }, 208 | "description": { 209 | "type": "string", 210 | "description": "Defined by `description` property of https://w3id.org/openbadges#BadgeClass" 211 | }, 212 | "image": { 213 | "$ref": "#/definitions/ImageUri", 214 | "description": "Defined by `image` property of https://w3id.org/openbadges#BadgeClass" 215 | }, 216 | "criteria": { 217 | "type": "object", 218 | "description": "Defined by `criteria` property of https://w3id.org/openbadges#BadgeClass. This field is required in Open Badges. If migrating from an earlier version, a quick change is to reuse the `description` field" 219 | }, 220 | "issuer": { 221 | "$ref": "https://w3id.org/blockcerts/schema/2.0/issuerSchema.json", 222 | "description": "Defined by `issuer` property of https://w3id.org/openbadges#BadgeClass, with Blockcerts extensions for blockchain verification of badges." 223 | }, 224 | "alignment": { 225 | "$ref": "#/definitions/AlignmentArray", 226 | "description": "Defined by `alignment` property of https://w3id.org/openbadges#BadgeClass" 227 | }, 228 | "tags": { 229 | "$ref": "#/definitions/TagsArray", 230 | "description": "Defined by `tags` property of https://w3id.org/openbadges#BadgeClass" 231 | }, 232 | "signatureLines": { 233 | "anyOf": [ 234 | { 235 | "$ref": "#/definitions/SignatureLine" 236 | }, 237 | { 238 | "type": "array", 239 | "items": { 240 | "$ref": "#/definitions/SignatureLine" 241 | } 242 | } 243 | ], 244 | "description": "Blockcerts extension: array of signature lines for display." 245 | } 246 | }, 247 | "required": [ 248 | "id", 249 | "name", 250 | "description", 251 | "image", 252 | "issuer", 253 | "criteria" 254 | ] 255 | } 256 | }, 257 | "properties": { 258 | "id": { 259 | "description": "Defined by `id` property in https://w3id.org/openbadges#Assertion. This may be an HTTP IRI, but only if the issuer plans to host the assertions on a long-term basis, or (at least) until their expiration. Otherwise it is recommended to use a `urn:uuid:`-formatted IRI.", 260 | "type": "string", 261 | "anyOf": [ 262 | { 263 | "type": "string", 264 | "pattern": "^urn:uuid:" 265 | }, 266 | { 267 | "type": "string", 268 | "format": "uri" 269 | } 270 | ] 271 | }, 272 | "type": { 273 | "$ref": "#/definitions/JsonLdType", 274 | "description": "Defined by `type` property of https://w3id.org/openbadges#Assertion" 275 | }, 276 | "recipient": { 277 | "$ref": "#/definitions/IdentityObject", 278 | "description": "Defined by `recipient` property of https://w3id.org/openbadges#Assertion, with Blockcerts extensions for recipient proof of ownership." 279 | }, 280 | "badge": { 281 | "$ref": "#/definitions/BadgeClass", 282 | "description": "Defined by `badge` property of https://w3id.org/openbadges#Assertion, with Blockcerts extensions for (display) signature images." 283 | }, 284 | "verification": { 285 | "$ref": "#/definitions/VerificationObject", 286 | "description": "Defined by `verification` property of https://w3id.org/openbadges#Assertion, with Blockcerts extensions for verification of badges on a blockchain." 287 | }, 288 | "issuedOn": { 289 | "$ref": "#/definitions/DateTime", 290 | "description": "Defined by `issuedOn` property of https://w3id.org/openbadges#Assertion" 291 | }, 292 | "image": { 293 | "$ref": "#/definitions/ImageUri", 294 | "description": "Defined by `image` property of https://w3id.org/openbadges#Assertion" 295 | }, 296 | "evidence": { 297 | "type": "string", 298 | "format": "uri", 299 | "description": "Defined by `evidence` property of https://w3id.org/openbadges#Assertion" 300 | }, 301 | "narrative": { 302 | "type": "string", 303 | "description": "Defined by `narrative` property of https://w3id.org/openbadges#Assertion" 304 | }, 305 | "expires": { 306 | "$ref": "#/definitions/DateTime", 307 | "description": "Defined by `expires` property of https://w3id.org/openbadges#Assertion" 308 | }, 309 | "recipientProfile": { 310 | "$ref": "#/definitions/RecipientProfile" 311 | }, 312 | "signature": { 313 | "$ref": "#/definitions/MerkleProof2017" 314 | } 315 | }, 316 | "required": [ 317 | "id", 318 | "type", 319 | "recipient", 320 | "badge", 321 | "verification", 322 | "issuedOn" 323 | ], 324 | "additionalProperties": true 325 | } 326 | -------------------------------------------------------------------------------- /cert_schema/2.0/signatureLineSchema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "title": "SignatureLine schema", 4 | "description": "An extension that allows issuers to add signature lines to the visual representation of the badge. This is not part of the cryptographic proof; it is for display purposes only.", 5 | "type": "object", 6 | "definitions": { 7 | "ImageUri": { 8 | "anyOf": [ 9 | { 10 | "type": "string", 11 | "pattern": "data:image/png;base64,", 12 | "description": "An image representative of the entity. In Blockcerts this is typically a data URI (https://en.wikipedia.org/wiki/Data_URI_scheme) embedded as a base-64 encoded PNG image, but it may also be a URI where the image may be found." 13 | }, 14 | { 15 | "type": "string", 16 | "format": "uri", 17 | "description": "IRI (typically HTTP) representing this signature image." 18 | } 19 | ] 20 | } 21 | }, 22 | "properties": { 23 | "image": { 24 | "$ref": "#/definitions/ImageUri" 25 | }, 26 | "jobTitle": { 27 | "type": "string", 28 | "description": "Job title of signer, http://schema.org/jobTitle" 29 | }, 30 | "name": { 31 | "type": "string", 32 | "description": "Full name of signer, http://schema.org/name" 33 | } 34 | }, 35 | "required": ["image"] 36 | } 37 | -------------------------------------------------------------------------------- /cert_schema/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | from cert_schema.jsonld_helpers import jsonld_document_loader, normalize_jsonld 3 | from cert_schema.schema_validator import validate_unsigned_v1_2, validate_v1_2, validate_v2 4 | 5 | from cert_schema.jsonld_helpers import BLOCKCERTS_V2_ALPHA_CONTEXT, BLOCKCERTS_V2_ALPHA_SCHEMA, BLOCKCERTS_V2_CONTEXT,\ 6 | BLOCKCERTS_V2_SCHEMA, BLOCKCERTS_V2_CANONICAL_CONTEXT, BLOCKCERTS_VOCAB, JSONLD_OPTIONS, \ 7 | OPEN_BADGES_V2_CANONICAL_CONTEXT, OPEN_BADGES_V2_CONTEXT, SECURITY_CONTEXT_URL 8 | 9 | from cert_schema.errors import * 10 | -------------------------------------------------------------------------------- /cert_schema/errors.py: -------------------------------------------------------------------------------- 1 | class BlockcertValidationError(Exception): 2 | pass 3 | 4 | 5 | class InvalidUrlError(Exception): 6 | pass 7 | -------------------------------------------------------------------------------- /cert_schema/jsonld_helpers.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | import json 3 | import os 4 | import re 5 | from copy import deepcopy 6 | 7 | import requests 8 | from pyld import jsonld 9 | from pyld.jsonld import JsonLdProcessor 10 | import validators 11 | 12 | from cert_schema.errors import * 13 | 14 | try: 15 | from urllib.request import urlopen 16 | except ImportError: 17 | from urllib2 import urlopen 18 | 19 | 20 | SECURITY_CONTEXT_URL = 'https://w3id.org/security/v1' 21 | OPEN_BADGES_V2_CONTEXT = 'https://openbadgespec.org/v2/context.json' 22 | OPEN_BADGES_V2_CANONICAL_CONTEXT = 'https://w3id.org/openbadges/v2' 23 | BLOCKCERTS_V2_ALPHA_CONTEXT = 'https://w3id.org/blockcerts/schema/2.0-alpha/context.json' 24 | BLOCKCERTS_V2_ALPHA_SCHEMA = 'https://w3id.org/blockcerts/schema/2.0-alpha/schema.json' 25 | BLOCKCERTS_V2_CONTEXT = 'https://w3id.org/blockcerts/schema/2.0/context.json' 26 | BLOCKCERTS_V2_SCHEMA = 'https://w3id.org/blockcerts/schema/2.0/schema.json' 27 | BLOCKCERTS_V2_CANONICAL_CONTEXT = 'https://w3id.org/blockcerts/v2' 28 | BLOCKCERTS_VOCAB = 'https://w3id.org/blockcerts/v2#' 29 | JSONLD_OPTIONS = {'algorithm': 'URDNA2015', 'format': 'application/nquads'} 30 | 31 | 32 | # Nonstandard contexts 33 | BLOCKCERTS_V2_ALPHA_CONTEXT_2 = 'https://www.blockcerts.org/schema/2.0-alpha/context.json' 34 | BLOCKCERTS_V2_CONTEXT_2 = 'https://www.blockcerts.org/schema/2.0/context.json' 35 | 36 | FALLBACK_VOCAB = 'http://fallback.org/' 37 | FALLBACK_CONTEXT = {'@vocab': FALLBACK_VOCAB} 38 | 39 | BASE_DIR = os.path.abspath(os.path.dirname(__file__)) 40 | 41 | JSON_LD_CONTEXT_V1_2 = os.path.join(BASE_DIR, '1.2/context.json') 42 | JSON_LD_CONTEXT_V2_0_ALPHA = os.path.join(BASE_DIR, '2.0-alpha/context.json') 43 | JSON_LD_CONTEXT_V2_0 = os.path.join(BASE_DIR, '2.0/context.json') 44 | OBI_JSON_LD_CONTEXT_V2 = os.path.join(BASE_DIR, '2.0/obi.json') 45 | 46 | PRELOADED_CONTEXTS = {} 47 | 48 | with open(OBI_JSON_LD_CONTEXT_V2) as data_file: 49 | obi_context = json.load(data_file) 50 | PRELOADED_CONTEXTS[OPEN_BADGES_V2_CONTEXT] = obi_context 51 | PRELOADED_CONTEXTS[OPEN_BADGES_V2_CANONICAL_CONTEXT] = obi_context 52 | 53 | with open(JSON_LD_CONTEXT_V2_0_ALPHA) as data_file: 54 | bc_context = json.load(data_file) 55 | PRELOADED_CONTEXTS[BLOCKCERTS_V2_ALPHA_CONTEXT] = bc_context 56 | PRELOADED_CONTEXTS[BLOCKCERTS_V2_ALPHA_CONTEXT_2] = bc_context 57 | 58 | with open(JSON_LD_CONTEXT_V2_0) as data_file: 59 | bc_context = json.load(data_file) 60 | PRELOADED_CONTEXTS[BLOCKCERTS_V2_CONTEXT] = bc_context 61 | PRELOADED_CONTEXTS[BLOCKCERTS_V2_CONTEXT_2] = bc_context 62 | PRELOADED_CONTEXTS[BLOCKCERTS_V2_CANONICAL_CONTEXT] = bc_context 63 | 64 | 65 | def to_loader_response(data, url): 66 | return { 67 | 'contextUrl': None, 68 | 'documentUrl': url, 69 | 'document': data 70 | } 71 | 72 | 73 | def load_document(url): 74 | """ 75 | :param url: 76 | :return: 77 | """ 78 | result = validators.url(url) 79 | if result: 80 | response = requests.get( 81 | url, headers={'Accept': 'application/ld+json, application/json'} 82 | ) 83 | return response.text 84 | raise InvalidUrlError('Could not validate ' + url) 85 | 86 | 87 | def jsonld_document_loader(url): 88 | """ 89 | Retrieves JSON-LD at the given URL. Propagates BlockcertValidationError is url is invalid 90 | or doesn't exist 91 | :param url: the URL to retrieve 92 | :return: JSON-LD at the URL 93 | """ 94 | data = load_document(url) 95 | return to_loader_response(data, url) 96 | 97 | 98 | def preloaded_context_document_loader(url, override_cache=False): 99 | if url in PRELOADED_CONTEXTS: 100 | context = PRELOADED_CONTEXTS[url] 101 | return to_loader_response(context, url) 102 | else: 103 | return jsonld_document_loader(url) 104 | 105 | 106 | def compact_with_json_ld_context(input_json, document_loader=preloaded_context_document_loader): 107 | options = {} 108 | if document_loader: 109 | options['documentLoader'] = document_loader 110 | with open(JSON_LD_CONTEXT_V1_2) as context_f: 111 | ctx = json.load(context_f) 112 | compacted = jsonld.compact(input_json, ctx, options=options) 113 | return compacted 114 | 115 | 116 | def normalize_jsonld(json_ld_to_normalize, document_loader=preloaded_context_document_loader, 117 | detect_unmapped_fields=False): 118 | """ 119 | Canonicalize the JSON-LD certificate. 120 | 121 | The detect_unmapped_fields parameter is a temporary, incomplete, workaround to detecting fields that do not 122 | correspond to items in the JSON-LD schemas. It works in the Blockcerts context because: 123 | - Blockcerts doesn't use a default vocab 124 | - fallback.org is not expected to occur 125 | 126 | Because unmapped fields get dropped during canonicalization, this uses a trick of adding 127 | {"@vocab": "http://fallback.org/"} to the json ld, which will cause any unmapped fields to be prefixed with 128 | http://fallback.org/. 129 | 130 | If a @vocab is already there (i.e. an issuer adds this in their extensions), then tampering will change the 131 | normalized form, hence the hash of the certificate, so we will still detect this during verification. 132 | 133 | This issue will be addressed in a first-class manner in the future by the pyld library. 134 | 135 | :param json_ld_to_normalize: 136 | :param document_loader 137 | :param detect_unmapped_fields: 138 | :return: 139 | """ 140 | json_ld = json_ld_to_normalize 141 | options = deepcopy(JSONLD_OPTIONS) 142 | if document_loader: 143 | options['documentLoader'] = document_loader 144 | 145 | if detect_unmapped_fields: 146 | json_ld = deepcopy(json_ld_to_normalize) 147 | prev_context = JsonLdProcessor.get_values(json_ld_to_normalize, '@context') 148 | add_fallback = True 149 | for pc in prev_context: 150 | if type(pc) is dict: 151 | for key, value in pc.items(): 152 | if key == '@vocab': 153 | # this already has a vocab; unmapped fields will be detected in the hash 154 | add_fallback = False 155 | break 156 | if add_fallback: 157 | prev_context.append(FALLBACK_CONTEXT) 158 | json_ld['@context'] = prev_context 159 | 160 | normalized = jsonld.normalize(json_ld, options=options) 161 | 162 | if detect_unmapped_fields and FALLBACK_VOCAB in normalized: 163 | unmapped_fields = [] 164 | for m in re.finditer('', normalized): 165 | unmapped_fields.append(m.group(0)) 166 | error_string = ', '.join(unmapped_fields) 167 | raise BlockcertValidationError( 168 | 'There are some fields in the certificate that do not correspond to the expected schema. This has likely been tampered with. Unmapped fields are: ' + error_string) 169 | return normalized 170 | 171 | 172 | if __name__ == '__main__': 173 | options = {} 174 | document_loader = preloaded_context_document_loader 175 | options['documentLoader'] = document_loader 176 | filename = '../examples/2.0/sample_valid-2.0.json' 177 | with open(filename) as data_f: 178 | data = json.load(data_f) 179 | compacted = compact_with_json_ld_context(data, document_loader) 180 | expanded = jsonld.expand(compacted, options=options) 181 | options = {'algorithm': 'URDNA2015', 'format': 'application/nquads'} 182 | if document_loader: 183 | options['documentLoader'] = document_loader 184 | normalized = jsonld.normalize(data, options) 185 | print(json.dumps(expanded, indent=2)) 186 | -------------------------------------------------------------------------------- /cert_schema/schema_validator.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | 3 | import json 4 | import logging 5 | 6 | import jsonschema 7 | import os 8 | 9 | from cert_schema.errors import BlockcertValidationError 10 | 11 | V2_SCHEMA_LOCAL_PATH = '2.0/schema.json' 12 | 13 | BASE_DIR = os.path.abspath(os.path.dirname(__file__)) 14 | SCHEMA_FILE_V1_1 = os.path.join(BASE_DIR, '1.1/certificate-schema-v1-1.json') 15 | SCHEMA_FILE_V1_2 = os.path.join(BASE_DIR, '1.2/blockchain-certificate-1.2.json') 16 | SCHEMA_FILE_V2_0_ALPHA = os.path.join(BASE_DIR, '2.0-alpha/schema.json') 17 | SCHEMA_FILE_V2_0 = os.path.join(BASE_DIR, V2_SCHEMA_LOCAL_PATH) 18 | 19 | SCHEMA_UNSIGNED_FILE_V1_2 = os.path.join(BASE_DIR, '1.2/certificate-document-1.2.json') 20 | 21 | 22 | def validate_v1_1(certificate_json): 23 | """ 24 | Propagates BlockcertValidationError on failure 25 | :param certificate_json: 26 | :return: 27 | """ 28 | 29 | with open(SCHEMA_FILE_V1_1) as schema_f: 30 | schema_json = json.load(schema_f) 31 | return validate_json(certificate_json, schema_json) 32 | 33 | 34 | def validate_v1_2(certificate_json): 35 | """ 36 | Propagates BlockcertValidationError on failure 37 | :param certificate_json: 38 | :return: 39 | """ 40 | 41 | with open(SCHEMA_FILE_V1_2) as schema_f: 42 | schema_json = json.load(schema_f) 43 | return validate_json(certificate_json, schema_json) 44 | 45 | 46 | def validate_v2(certificate_json): 47 | with open(SCHEMA_FILE_V2_0) as schema_f: 48 | schema_json = json.load(schema_f) 49 | return validate_json(certificate_json, schema_json) 50 | 51 | 52 | def validate_v2_alpha(certificate_json): 53 | with open(SCHEMA_FILE_V2_0_ALPHA) as blockcerts_schema: 54 | schema_v2 = json.load(blockcerts_schema) 55 | result = validate_json(certificate_json, schema_v2) 56 | return result 57 | 58 | 59 | def validate_unsigned_v1_2(certificate_json): 60 | """ 61 | Raises or propagates BlockcertValidationError on failure 62 | :param certificate_json: 63 | :return: 64 | """ 65 | with open(SCHEMA_UNSIGNED_FILE_V1_2) as schema_f: 66 | schema_json = json.load(schema_f) 67 | # first a conditional check not done in the json schema 68 | if certificate_json['recipient']['hashed'] and not certificate_json['recipient']['salt']: 69 | logging.error('certificate is hashed but has no salt') 70 | raise jsonschema.exceptions.ValidationError('certificate is hashed but has no salt') 71 | 72 | return validate_json(certificate_json, schema_json) 73 | 74 | 75 | def validate_json(certificate_json, schema_json): 76 | """ 77 | If no exception is raised, the instance is valid. Raises BlockcertValidationError is validation fails. 78 | :param certificate_json: 79 | :param schema_json: 80 | :return: 81 | """ 82 | try: 83 | jsonschema.validate(certificate_json, schema_json) 84 | return True 85 | except jsonschema.exceptions.ValidationError as ve: 86 | logging.error(ve, exc_info=True) 87 | raise BlockcertValidationError(ve) 88 | 89 | 90 | def validate(data_file, schema_file): 91 | with open(data_file) as data_f, open(schema_file) as schema_f: 92 | data = json.load(data_f) 93 | schema = json.load(schema_f) 94 | return validate_json(data, schema) 95 | 96 | 97 | if __name__ == '__main__': 98 | valid = validate('../../examples/1.1/sample_unsigned_cert-1.1.json', 99 | '../1.1/certificate-schema-v1-1.json') 100 | print('certificate is valid? ' + str(valid)) 101 | 102 | valid = validate('../../examples/1.1/sample_signed_cert-1.1.json', 103 | '../1.1/certificate-schema-v1-1.json') 104 | print('certificate is valid? ' + str(valid)) 105 | 106 | valid = validate('../../examples/1.2/sample_signed_cert-1.2.json', 107 | '../1.2/blockchain-certificate-1.2.json') 108 | print('certificate is valid? ' + str(valid)) 109 | -------------------------------------------------------------------------------- /docs/assertion-schema.md: -------------------------------------------------------------------------------- 1 | ## Assertion Schema 2 | 3 | Extends the Open Badges Assertion Schema for certificates on the blockchain 4 | 5 | The schema defines the following properties: 6 | 7 | ### `@context` (JsonLdContext) 8 | 9 | A link to a valid JSON-LD context file, that maps term names to contexts. Blockchain Certificate contexts may also define JSON-schema to validate Blockchain Certificates against. In a Blockchain Certificate Object, this will almost always be a string:uri to a single context file, but might rarely be an array of links or context objects instead. This schema also allows direct mapping of terms to IRIs by using an object as an option within an array. 10 | 11 | This property must be one of the following types: 12 | 13 | * `string` 14 | * `array` 15 | 16 | ### `type` (JsonLdType, required) 17 | 18 | A type or an array of types that the Blockchain Certificate object represents. The first or only item should be ‘Assertion’, and any others should each be an IRI (usually a URL) corresponding to a definition of the type itself. In almost all cases, there will be only one type: ‘Assertion’ 19 | 20 | This property must be one of the following types: 21 | 22 | * `string` 23 | * `array` 24 | 25 | ### `id` (string, required) 26 | 27 | URI that links to the certificate on the viewer. 28 | 29 | ### `uid` (string, required) 30 | 31 | Unique identifier, in GUID format. V1.2 change: string pattern changed to guid 32 | 33 | Additional restrictions: 34 | 35 | * Regex pattern: `[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}` 36 | 37 | ### `issuedOn` (DateTime, required) 38 | 39 | Date the certificate JSON was created. This uses the Open Badges DateTime type, defined as one of: 40 | 41 | * ISO 8601 date format string yyyy-MM-dd'T'HH:mm:ss.SSS, where the time component is optional and time zone is optional 42 | * 10-digit UNIX timestamp, epoch time 43 | 44 | ### `evidence` (string) 45 | 46 | URL of the work that the recipient did to earn the achievement. This can be a page that links out to other pages if linking directly to the work is infeasible. V1.2 made this field optional, which is consistent with OBI spec. 47 | 48 | ### `expires` (DateTime) 49 | 50 | If the achievement has some notion of expiry, this indicates a date when a badge should no longer be considered valid. 51 | 52 | This uses the Open Badges DateTime type, defined as one of: 53 | 54 | * ISO 8601 date format string yyyy-MM-dd'T'HH:mm:ss.SSS, where the time component is optional and time zone is optional 55 | * 10-digit UNIX timestamp, epoch time 56 | 57 | If the ISO 8601 format is used and no time zone is provided, the certificate verifiers will assume UTC. 58 | 59 | ### `image:signature` (object) 60 | 61 | A single signature image, or array of objects with fields image and jobTitle. V1.2 change: support multiple signatures 62 | 63 | Must be one of the following types: 64 | 65 | * `string` 66 | * `array` 67 | 68 | If type is string, then value must be a Data URI; a base-64 encoded png image of the certificate’s image. https://en.wikipedia.org/wiki/Data_URI_scheme 69 | 70 | If type is array, then array items are objects consisting of properties: 71 | 72 | `jobTitle`: (string) 73 | 74 | Title of the undersigned. http://schema.org/Person#jobTitle 75 | 76 | `image`: (string) 77 | 78 | Data URI; a base-64 encoded png image of the certificate’s image. https://en.wikipedia.org/wiki/Data_URI_scheme 79 | 80 | 81 | Additional restrictions: 82 | 83 | * Image regex pattern: `data:image/png;base64,` 84 | -------------------------------------------------------------------------------- /docs/certificate-document.md: -------------------------------------------------------------------------------- 1 | ## Certificate Document Schema Version 1.2 2 | 3 | The complete certificate document, including the assertion, certificate, and issuer. Doesn’t include the blockchain receipt. This part is hashed and placed on the blockchain 4 | 5 | The schema defines the following properties: 6 | 7 | ### `@context` (JsonLdContext) 8 | 9 | A link to a valid JSON-LD context file, that maps term names to contexts. Blockchain Certificate contexts may also define JSON-schema to validate Blockchain Certificates against. In a Blockchain Certificate Object, this will almost always be a string:uri to a single context file, but might rarely be an array of links or context objects instead. This schema also allows direct mapping of terms to IRIs by using an object as an option within an array. 10 | 11 | This property must be one of the following types: 12 | 13 | * `string` 14 | * `array` 15 | 16 | ### `type` (JsonLdType, required) 17 | 18 | A type or an array of types that the Blockchain Certificate object represents. The first or only item should be ‘CertificateDocument’, and any others should each be an IRI (usually a URL) corresponding to a definition of the type itself. In almost all cases, there will be only one type: ‘CertificateDocument’ 19 | 20 | This property must be one of the following types: 21 | 22 | * `string` 23 | * `array` 24 | 25 | ### `certificate` (Certificate, required) 26 | 27 | [Certificate](certificate-schema.html) 28 | 29 | ### `assertion` (Assertion, required) 30 | 31 | [Assertion](assertion-schema.html) 32 | 33 | ### `verify` (VerificationObject, required) 34 | 35 | V1.2 notice: the Blockchain Certificates VerificationObject will change in the next schema version to be consistent with OBI VerificationObjects. This work is in progress. 36 | 37 | Properties of the `VerificationObject` object: 38 | 39 | `attribute-signed` (string, required) 40 | 41 | Name of the attribute in the json that is signed by the issuer’s private key. Default is ‘uid’, referring to the uid attribute. 42 | 43 | `type` (string, enum, required) 44 | 45 | Name of the signing method. Default is ‘ECDSA(secp256k1)’, referring to the Blockchain Certificates method of signing messages with the issuer’s private key. 46 | 47 | This element must be one of the following enum values: 48 | 49 | * `hosted` 50 | * `signed` 51 | * `ECDSA(secp256k1)` 52 | 53 | `signer` (string) 54 | 55 | URI where issuer’s public key is presented. Default is https://[domain]/keys/[org-abbr]-certs-public-key.asc. V1.2 change: this field is optional 56 | 57 | ### `recipient` (Recipient, required) 58 | 59 | Properties of the `Recipient` object: 60 | 61 | `familyName` (string, required) 62 | 63 | Family name of the recipient. http://schema.org/Person#familyName 64 | 65 | `identity` (string, required) 66 | 67 | String that represents a recipient’s identity. By default, it is an email address. 68 | 69 | `type` (string, required) 70 | 71 | Type of value in the identity field. Default is ‘email’. 72 | 73 | `hashed` (boolean, required) 74 | 75 | Describes if the value in the identity field is hashed or not. We strongly recommend that the issuer hash the identy to protect the recipient. 76 | 77 | `salt` (string) 78 | 79 | per the OBI standard, if the recipient identity is hashed, then this should contain the string used to salt the hash 80 | 81 | `publicKey` (string, required) 82 | 83 | Bitcoin address (compressed public key, usually 24 characters) of the recipient. V1.2 change: renamed from pubkey 84 | 85 | `revocationKey` (string) 86 | 87 | Issuer revocation key for the recipient, optional. Bitcoin address (compressed public key, usually 24 characters) of the recipient. 88 | 89 | `givenName` (string, required) 90 | 91 | Given name of the recipient. http://schema.org/Person#givenName 92 | -------------------------------------------------------------------------------- /docs/certificate-schema.md: -------------------------------------------------------------------------------- 1 | ## Certificate Schema 2 | 3 | Extends the Open Badges Certificate Schema for certificates on the blockchain 4 | 5 | The schema defines the following properties: 6 | 7 | ### `@context` (JsonLdContext) 8 | 9 | A link to a valid JSON-LD context file, that maps term names to contexts. Blockchain Certificate contexts may also define JSON-schema to validate Blockchain Certificates against. In a Blockchain Certificate Object, this will almost always be a string:uri to a single context file, but might rarely be an array of links or context objects instead. This schema also allows direct mapping of terms to IRIs by using an object as an option within an array. 10 | 11 | This property must be one of the following types: 12 | 13 | * `string` 14 | * `array` 15 | 16 | ### `type` (JsonLdType) 17 | 18 | A type or an array of types that the Blockchain Certificate object represents. The first or only item should be ‘Certificate’, and any others should each be an IRI (usually a URL) corresponding to a definition of the type itself. In almost all cases, there will be only one type: ‘Certificate’ 19 | 20 | This property must be one of the following types: 21 | 22 | * `string` 23 | * `array` 24 | 25 | ### `id` (string) 26 | 27 | URI link to a JSON that describes the type of certificate. Default format is https://[domain]/criteria/[year]/[month]/[certificate_title].json. V1.2 change: this field is optional. 28 | 29 | ### `name` (string, required) 30 | 31 | Name (or title) of the certificate. V1.2 change: renamed from ‘title’ to be consistent with OBI schema 32 | 33 | ### `description` (string, required) 34 | 35 | ### `image` (string, required) 36 | 37 | Data URI; a base-64 encoded png image of the certificate’s image. https://en.wikipedia.org/wiki/Data_URI_scheme 38 | 39 | Additional restrictions: 40 | 41 | * Regex pattern: `data:image/png;base64,` 42 | 43 | ### `criteria` (string) 44 | 45 | ### `issuer` (Issuer, required) 46 | 47 | [Issuer](issuer.html) 48 | 49 | ### `alignment` 50 | 51 | ### `tags` 52 | 53 | ### `language` (string) 54 | 55 | Represents the ieft language and ieft country codes. Format is [ieft_language]-[IEFT_COUNTRY]. V1.2 changes: this field is optional 56 | 57 | Additional restrictions: 58 | 59 | * Regex pattern: `[a-z]{2}-[A-Z]{2}` 60 | 61 | ### `subtitle` (string) 62 | 63 | Subtitle of the certificate. V1.2 changes: this type is now string, and this field is optional 64 | -------------------------------------------------------------------------------- /docs/issuer-id.md: -------------------------------------------------------------------------------- 1 | ## Issuer Identification Schema 2 | 3 | The schema defines the following properties: 4 | 5 | ### `issuerKeys` (array, required) 6 | 7 | list of issuer keys, listed in descending date order (most recent first). V1.2 change: renamed from issuer_key, added optional invalidated field. 8 | 9 | The object is an array with all elements of the type `object`. 10 | 11 | The array object has the following properties: 12 | 13 | `date` (string, required) 14 | 15 | ISO-8601 formatted date time the key was activated. 16 | 17 | `key` (string, required) 18 | 19 | Bitcoin address (compressed public key, usually 24 characters) that the issuer uses to issue the certificates. 20 | 21 | `invalidated` (string) 22 | 23 | Optional ISO-8601 formatted date time the key was invalidated. 24 | 25 | ### `revocationKeys` (array, required) 26 | 27 | list of revocation keys, listed in descending date order (most recent first). V1.2 changes: renamed from revocation_key, added optional invalidated field. 28 | 29 | The object is an array with all elements of the type `object`. 30 | 31 | The array object has the following properties: 32 | 33 | `date` (string, required) 34 | 35 | ISO-8601 formatted date time the key was activated. 36 | 37 | `key` (string, required) 38 | 39 | Bitcoin address (compressed public key, usually 24 characters) that the issuer uses to revoke the certificates. 40 | 41 | `invalidated` (string) 42 | 43 | Optional ISO-8601 formatted date time the key was invalidated. 44 | 45 | ### `id` (string, required) 46 | 47 | The URL of the issuer's website or homepage 48 | 49 | ### `name` (string, required) 50 | 51 | Human-readable name of the issuing entity 52 | 53 | ### `email` (string, required) 54 | 55 | Contact address for the individual or organization. 56 | 57 | ### `url` (string, required) 58 | 59 | The URL where the issuer's certificates can be found 60 | 61 | ### `introductionURL` (string, required) 62 | 63 | The URL hosting the issuer's introduction endpoint 64 | 65 | ### `image` (string, required) 66 | 67 | Data URI; a base-64 encoded png image of the issuer's image. https://en.wikipedia.org/wiki/Data_URI_scheme 68 | 69 | Additional restrictions: 70 | 71 | * Regex pattern: `data:image/png;base64,` -------------------------------------------------------------------------------- /docs/issuer.md: -------------------------------------------------------------------------------- 1 | ## Issuer Schema 2 | 3 | Extends the Open Badges Issuer Schema for certificates on the blockchain 4 | 5 | The schema defines the following properties: 6 | 7 | ### `@context` (JsonLdContext) 8 | 9 | A link to a valid JSON-LD context file, that maps term names to contexts. Blockchain Certificate contexts may also define JSON-schema to validate Blockchain Certificates against. In a Blockchain Certificate Object, this will almost always be a string:uri to a single context file, but might rarely be an array of links or context objects instead. This schema also allows direct mapping of terms to IRIs by using an object as an option within an array. 10 | 11 | This property must be one of the following types: 12 | 13 | * `string` 14 | * `array` 15 | 16 | ### `type` (JsonLdType) 17 | 18 | A type or an array of types that the Blockchain Certificate object represents. The first or only item should be ‘Issuer’, and any others should each be an IRI (usually a URL) corresponding to a definition of the type itself. In almost all cases, there will be only one type: ‘Issuer’ 19 | 20 | This property must be one of the following types: 21 | 22 | * `string` 23 | * `array` 24 | 25 | ### `id` (string, required) 26 | 27 | Link to a JSON that details the issuer’s issuing and recovation keys. Default is https://[domain]/issuer/[org_abbr]-issuer.json. Included for (near) backward compatibility with open badges specification 1.1 28 | 29 | ### `image` (BCBadgeImage) 30 | 31 | An image representative of the entity. This overrides BadgeImage from OBI because oneOf, compared to anyOf, was failing validation 32 | 33 | ### `name` (string, required) 34 | 35 | Human-readable name of the issuing entity 36 | 37 | ### `url` (string, required) 38 | 39 | The URL of the issuer’s website or homepage 40 | 41 | ### `description` (string) 42 | 43 | A text description of the issuing organization 44 | 45 | ### `email` (string) 46 | 47 | Contact address for the individual or organization. 48 | 49 | ### `revocationList` (string) 50 | -------------------------------------------------------------------------------- /docs/issuer_schema-2.md: -------------------------------------------------------------------------------- 1 | ## IssuerProfile schema 2 | 3 | Blockcerts 2.0 Issuer Identification (Profile) schema. Extends https://w3id.org/openbadges#Profile, a type that is embedded in an Open Badge and/or hosted at an issuer URI. Blockcerts specializes the Issuer Profile type into 2 schemas: the core that is embedded in the certificate (which matches the Open Badges Profile type), and one that is to be hosted at an issuer URI, to support blockchain verification of claims. This schema describes the latter. The issuer-hosted Profile is used in the Blockcerts verification process to look up the current list of public keys claimed by the issuer. This also defines an `introductionURL` which may be used by recipients (or software agents) to submit an introduction to the issuer. 4 | 5 | The schema defines the following properties: 6 | 7 | ### `publicKey` (array, required) 8 | 9 | Array of CryptographicKey (https://web-payments.org/vocabs/security#Key) references or objects. Entries may be dereferencable URIs of a document describing a CryptographicKey, or an embedded description of a CryptographicKey. 10 | 11 | The elements of the array must match *at least one* of the following properties: 12 | 13 | ### (string) 14 | 15 | Cryptographic key 16 | 17 | ### (CryptographicKey) 18 | 19 | ### `introductionURL` (string) 20 | 21 | Blockcerts extension: URI where potential recipients (or their agents) should submit introductions, including recipient public key. If the issuer supports certificate wallet introductions, this field should specify the endpoint for use by certificate wallets. Otherwise, it can represent a URI enabling some other form of introduction; for example an HTTP IRI for a web form that to be filled out by the recipient. 22 | 23 | 24 | ## Sub Schemas 25 | 26 | The schema defines the following additional types: 27 | 28 | ### `JsonLdContext` 29 | 30 | A link to a valid JSON-LD context, or array of JSON-LD contexts 31 | 32 | This property must be one of the following types: 33 | 34 | * `string` 35 | * `array` 36 | 37 | ### `JsonLdType` 38 | 39 | A type or an array of types defined in a referenced JSON-LD context. 40 | 41 | This property must be one of the following types: 42 | 43 | * `string` 44 | * `array` 45 | 46 | ### `ImageUri` (string) 47 | 48 | An image representative of the entity. In Blockcerts this is typically a data URI embedded as a base-64 encoded PNG image, but it may also be a URI where the image may be found. 49 | 50 | ### `DateTime` (string) 51 | 52 | ISO 8601 datetime 53 | 54 | ### `CryptographicKey` (object) 55 | 56 | Defined by https://web-payments.org/vocabs/security#Key 57 | 58 | Properties of the `CryptographicKey` object: 59 | 60 | #### `id` (string) 61 | 62 | Issuer public key or blockchain address IRI with `:` prefix. For Bitcoin transactions, this would be the issuer public address prefixed with `ecdsa-koblitz-pubkey:`; e.g. `ecdsa-koblitz-pubkey:14RZvYazz9H2DC2skBfpPVxax54g4yabxe` 63 | 64 | Additional restrictions: 65 | 66 | * Regex pattern: `^ecdsa-koblitz-pubkey:` 67 | 68 | #### `created` (DateTime, required) 69 | 70 | #### `expires` (DateTime) 71 | 72 | #### `revoked` (DateTime) 73 | 74 | ### `Profile` (undefined) 75 | 76 | Defined by https://w3id.org/openbadges#Profile. This type is used in certificates, and in the issuer-hosted identification page. The minimal set of properties required in the certificate are `id` and `type`. In this case, additional issuer-identification properties are assumed to be available at the issuer-hosted identification page. 77 | 78 | #### `id` (string, required) 79 | 80 | Defined by `id` property of https://w3id.org/openbadges#Profile 81 | 82 | #### `type` (JsonLdType, required) 83 | 84 | Defined by `type` property of https://w3id.org/openbadges#Profile 85 | 86 | #### `name` (string) 87 | 88 | Defined by `name` property of https://w3id.org/openbadges#Profile 89 | 90 | #### `url` (string) 91 | 92 | Defined by `url` property of https://w3id.org/openbadges#Profile 93 | 94 | #### `telephone` (string) 95 | 96 | Defined by `telephone` property of https://w3id.org/openbadges#Profile 97 | 98 | #### `description` (string) 99 | 100 | Defined by `description` property of https://w3id.org/openbadges#Profile 101 | 102 | #### `image` (ImageUri) 103 | 104 | Defined by `image` property of https://w3id.org/openbadges#Profile 105 | 106 | #### `email` (string) 107 | 108 | Defined by `email` property of https://w3id.org/openbadges#Profile 109 | 110 | #### `revocationList` 111 | 112 | Defined by `revocationList` property of https://w3id.org/openbadges#Profile. If embedded in a Blockcert and the issuer-hosted Profile, the value in the Blockcert should take preference. 113 | 114 | -------------------------------------------------------------------------------- /docs/issuer_schema.md: -------------------------------------------------------------------------------- 1 | ## IssuerProfile schema 2 | 3 | Blockcerts 2.0 Issuer Identification (Profile) schema. Extends [https://w3id.org/openbadges#Profile](https://w3id.org/openbadges#Profile), a type that is embedded in an Open Badge and/or hosted at an issuer URI. Blockcerts specializes the Issuer Profile type into 2 schemas: the core that is embedded in the certificate (which matches the Open Badges Profile type), and one that is to be hosted at an issuer URI, to support blockchain verification of claims. This schema describes the latter. The issuer-hosted Profile is used in the Blockcerts verification process to look up the current list of public keys claimed by the issuer. This also defines an `introductionURL` which may be used by recipients (or software agents) to submit an introduction to the issuer. 4 | 5 | The schema defines the following additional properties to the Profile schema: 6 | 7 | ### `publicKeys` (array, required) 8 | 9 | Array of CryptographicKey ([https://web-payments.org/vocabs/security#Key](https://web-payments.org/vocabs/security#Key)) references or objects. Entries may be dereferencable URIs of a document describing a CryptographicKey, or an embedded description of a CryptographicKey. 10 | 11 | The elements of the array must match *at least one* of the following properties: 12 | 13 | * `string`: Cryptographic key URI 14 | * Format: `uri` 15 | * `CryptographicKey` 16 | 17 | ### `introductionURL` (string) 18 | 19 | Blockcerts extension: URI where potential recipients (or their agents) should submit introductions, including recipient public key. If the issuer supports certificate wallet introductions, this field should specify the endpoint for use by certificate wallets. Otherwise, it can represent a URI enabling some other form of introduction; for example an HTTP IRI for a web form that to be filled out by the recipient. 20 | 21 | Additional restrictions: 22 | 23 | * Format: `uri` 24 | 25 | ### allOf (Profile) 26 | 27 | The IssuerProfile schema includes all properties of the Profile schema 28 | 29 | ### Required fields 30 | 31 | * `id` 32 | * `type` 33 | * `name` 34 | * `url` 35 | * `publicKeys` 36 | 37 | --- 38 | 39 | # Sub Schemas 40 | 41 | 42 | The schema defines the following additional types: 43 | 44 | ## `Profile` 45 | 46 | Defined by [https://w3id.org/openbadges#Profile](https://w3id.org/openbadges#Profile). This type is used in certificates, and in the issuer-hosted identification page. The minimal set of properties required in the certificate are `id` and `type`. In this case, additional issuer-identification properties are assumed to be available at the issuer-hosted identification page. 47 | 48 | ### `id` (string, required) 49 | 50 | Defined by `id` property of [https://w3id.org/openbadges#Profile](https://w3id.org/openbadges#Profile) 51 | 52 | Additional restrictions: 53 | 54 | * Format: `uri` 55 | 56 | ### `type` (JsonLdType, required) 57 | 58 | Defined by `type` property of [https://w3id.org/openbadges#Profile](https://w3id.org/openbadges#Profile) 59 | 60 | ### `name` (string) 61 | 62 | Defined by `name` property of [https://w3id.org/openbadges#Profile](https://w3id.org/openbadges#Profile) 63 | 64 | ### `url` (string) 65 | 66 | Defined by `url` property of [https://w3id.org/openbadges#Profile](https://w3id.org/openbadges#Profile) 67 | 68 | Additional restrictions: 69 | 70 | * Format: `uri` 71 | 72 | ### `telephone` (string) 73 | 74 | Defined by `telephone` property of [https://w3id.org/openbadges#Profile](https://w3id.org/openbadges#Profile) 75 | 76 | ### `description` (string) 77 | 78 | Defined by `description` property of [https://w3id.org/openbadges#Profile](https://w3id.org/openbadges#Profile) 79 | 80 | ### `image` (ImageUri) 81 | 82 | Defined by `image` property of [https://w3id.org/openbadges#Profile](https://w3id.org/openbadges#Profile) 83 | 84 | ### `email` (string) 85 | 86 | Defined by `email` property of [https://w3id.org/openbadges#Profile](https://w3id.org/openbadges#Profile) 87 | 88 | ### `revocationList` (string) 89 | 90 | Defined by `revocationList` property of [https://w3id.org/openbadges#Profile](https://w3id.org/openbadges#Profile). If embedded in a Blockcert and the issuer-hosted Profile, the value in the Blockcert should take preference. 91 | 92 | Additional restrictions: 93 | 94 | * Format: `uri` 95 | 96 | 97 | ## `CryptographicKey` (object) 98 | 99 | Defined by [https://web-payments.org/vocabs/security#Key](https://web-payments.org/vocabs/security#Key) 100 | 101 | Properties of the `CryptographicKey` object: 102 | 103 | ### `publicKey` (string, required) 104 | 105 | Issuer public key or blockchain address IRI with `:` prefix. For Bitcoin transactions, this would be the issuer public address prefixed with `ecdsa-koblitz-pubkey:`; e.g. `ecdsa-koblitz-pubkey:14RZvYazz9H2DC2skBfpPVxax54g4yabxe` 106 | 107 | Additional restrictions: 108 | 109 | * Regex pattern: `^ecdsa-koblitz-pubkey:` 110 | 111 | ### `created` (DateTime, required) 112 | 113 | ### `expires` (DateTime) 114 | 115 | ### `revoked` (DateTime) 116 | 117 | ## `JsonLdContext` 118 | 119 | A link to a valid JSON-LD context, or array of JSON-LD contexts 120 | 121 | This property must be one of the following types: 122 | 123 | * `string` 124 | * `array` 125 | 126 | ## `JsonLdType` 127 | 128 | A type or an array of types defined in a referenced JSON-LD context. 129 | 130 | This property must be one of the following types: 131 | 132 | * `string` 133 | * `array` 134 | 135 | ## `ImageUri` (string) 136 | 137 | An image representative of the entity. In Blockcerts this is typically a data URI embedded as a base-64 encoded PNG image, but it may also be a URI where the image may be found. 138 | 139 | This property may be any of the following types: 140 | 141 | * `string` 142 | * Pattern: `^data:` 143 | * `string` 144 | * Format: `uri` 145 | 146 | ## `ISODateTime` (string) 147 | 148 | ISO 8601 date format string `yyyy-MM-dd'T'HH:mm:ss.SSS` with optional `.SSS` milliseconds 149 | 150 | ## `UNIXTimeStamp` (integer) 151 | 152 | 10-digit UNIX timestamp, epoch time 153 | 154 | ## `DateTime` 155 | 156 | This property may be any of the following types: 157 | 158 | * `ISODateTime` 159 | * `UNIXTimeStamp` 160 | -------------------------------------------------------------------------------- /docs/json-context.md: -------------------------------------------------------------------------------- 1 | ## Blockchain Certificates JSON LD Context 2 | 3 | { 4 | "@context": [ 5 | { 6 | "id": "@id", 7 | "type": "@type", 8 | "bc": "https://w3id.org/blockcerts#", 9 | "obi": "https://w3id.org/openbadges#", 10 | "cp": "https://w3id.org/chainpoint#", 11 | "extensions": "https://w3id.org/openbadges/extensions#", 12 | "validation": "obi:validation", 13 | "xsd": "http://www.w3.org/2001/XMLSchema#", 14 | "schema": "http://schema.org/", 15 | "sec": "https://w3id.org/security#", 16 | "Assertion": "bc:Assertion", 17 | "Certificate": "bc:Certificate", 18 | "Issuer": "bc:Issuer", 19 | "BlockchainCertificate": "bc:BlockchainCertificate", 20 | "CertificateDocument": "bc:CertificateDocument", 21 | "issuer": { 22 | "@id": "bc:issuer", 23 | "@type": "@id" 24 | }, 25 | "recipient": { 26 | "@id": "bc:recipient", 27 | "@type": "@id" 28 | }, 29 | "blockchaincertificate": { 30 | "@id": "bc:blockchaincertificate", 31 | "@type": "@id" 32 | }, 33 | "certificate": { 34 | "@id": "bc:certificate", 35 | "@type": "@id" 36 | }, 37 | "document": { 38 | "@id": "bc:document", 39 | "@type": "@id" 40 | }, 41 | "assertion": { 42 | "@id": "bc:assertion", 43 | "@type": "@id" 44 | }, 45 | "verify": { 46 | "@id": "bc:verify", 47 | "@type": "@id" 48 | }, 49 | "recipient": { 50 | "@id": "bc:recipient", 51 | "@type": "@id" 52 | }, 53 | "receipt": { 54 | "@id": "bc:receipt", 55 | "@type": "@id" 56 | }, 57 | "publicKey": { 58 | "@id": "bc:publicKey" 59 | }, 60 | "revocationKey": { 61 | "@id": "bc:revocationKey" 62 | }, 63 | "image:signature": { 64 | "@id": "bc:image:signature" 65 | }, 66 | "signature": { 67 | "@id": "bc:signature" 68 | }, 69 | "familyName": { 70 | "@id": "schema:familyName" 71 | }, 72 | "givenName": { 73 | "@id": "schema:givenName" 74 | }, 75 | "signer": { 76 | "@id": "bc:signer", 77 | "@type": "@id" 78 | }, 79 | "attribute-signed": { 80 | "@id": "bc:attribute-signed" 81 | }, 82 | "ECDSA(secp256k1)": "bc:SignedBadge", 83 | "subtitle": { 84 | "@id": "bc:subtitle" 85 | }, 86 | "email": "schema:email", 87 | "hashed": { 88 | "@id": "obi:hashed", 89 | "@type": "xsd:boolean" 90 | }, 91 | "image": { 92 | "@id": "schema:image", 93 | "@type": "@id" 94 | }, 95 | "salt": { 96 | "@id": "obi:salt" 97 | }, 98 | "identity": { 99 | "@id": "obi:identityHash" 100 | }, 101 | "issuedOn": { 102 | "@id": "obi:issueDate", 103 | "@type": "xsd:dateTime" 104 | }, 105 | "expires": { 106 | "@id": "sec:expiration", 107 | "@type": "xsd:dateTime" 108 | }, 109 | "evidence": { 110 | "@id": "obi:evidence", 111 | "@type": "@id" 112 | }, 113 | "criteria": { 114 | "@id": "obi:criteria", 115 | "@type": "@id" 116 | }, 117 | "tags": { 118 | "@id": "schema:keywords" 119 | }, 120 | "alignment": { 121 | "@id": "obi:alignment", 122 | "@type": "@id" 123 | }, 124 | "revocationList": { 125 | "@id": "obi:revocationList", 126 | "@type": "@id" 127 | }, 128 | "name": { 129 | "@id": "schema:name" 130 | }, 131 | "description": { 132 | "@id": "schema:description" 133 | }, 134 | "url": { 135 | "@id": "schema:url", 136 | "@type": "@id" 137 | }, 138 | "uid": { 139 | "@id": "obi:uid" 140 | }, 141 | "revocationList": "obi:revocationList", 142 | "TypeValidation": "obi:TypeValidation", 143 | "FrameValidation": "obi:FrameValidation", 144 | "validatesType": "obi:validatesType", 145 | "validationSchema": "obi:validationSchema", 146 | "validationFrame": "obi:validationFrame", 147 | "ChainpointSHA224v2": "cp:ChainpointSHA224v2", 148 | "ChainpointSHA256v2": "cp:ChainpointSHA256v2", 149 | "ChainpointSHA384v2": "cp:ChainpointSHA384v2", 150 | "ChainpointSHA512v2": "cp:ChainpointSHA512v2", 151 | "ChainpointSHA3-224v2": "cp:ChainpointSHA3-224v2", 152 | "ChainpointSHA3-256v2": "cp:ChainpointSHA3-256v2", 153 | "ChainpointSHA3-384v2": "cp:ChainpointSHA3-384v2", 154 | "ChainpointSHA3-512v2": "cp:ChainpointSHA3-512v2", 155 | "BTCOpReturn": "cp:BTCOpReturn", 156 | "targetHash": "cp:targetHash", 157 | "merkleRoot": "cp:merkleRoot", 158 | "proof": "cp:proof", 159 | "anchors": "cp:anchors", 160 | "sourceId": "cp:sourceId", 161 | "right": "cp:right", 162 | "left": "cp:left" 163 | } 164 | ], 165 | "validation": [ 166 | { 167 | "type": "TypeValidation", 168 | "validatesType": "Assertion", 169 | "validationSchema": "http://w3id.org/blockcerts/schema/1.2/assertion-1.2.json" 170 | }, 171 | { 172 | "type": "TypeValidation", 173 | "validatesType": "Certificate", 174 | "validationSchema": "http://w3id.org/blockcerts/schema/1.2/certificate-1.2.json" 175 | }, 176 | { 177 | "type": "TypeValidation", 178 | "validatesType": "Issuer", 179 | "validationSchema": "http://w3id.org/blockcerts/schema/1.2/issuer-1.2.json" 180 | }, 181 | { 182 | "type": "TypeValidation", 183 | "validatesType": "CertificateDocument", 184 | "validationSchema": "http://w3id.org/blockcerts/schema/1.2/certificate-document-1.2.json" 185 | }, 186 | { 187 | "type": "TypeValidation", 188 | "validatesType": "BlockchainCertificate", 189 | "validationSchema": "http://w3id.org/blockcerts/schema/1.2/blockchain-certificate-1.2.json" 190 | }, 191 | { 192 | "type": "TypeValidation", 193 | "validatesType": "BlockchainReceipt", 194 | "validationSchema": "http://w3id.org/blockcerts/schema/1.2/blockchain-receipt-1.2.json" 195 | } 196 | ] 197 | } 198 | -------------------------------------------------------------------------------- /docs/json-schema.md: -------------------------------------------------------------------------------- 1 | ## Blockchain Certificate JSON Schema 2 | 3 | A schema for representing certificates on the blockchain 4 | 5 | The schema defines the following properties: 6 | 7 | ### `@context` (JsonLdContext, required) 8 | 9 | A link to a valid JSON-LD context file, that maps term names to contexts. Blockchain Certificate contexts may also define JSON-schema to validate Blockchain Certificates against. In a Blockchain Certificate Object, this will almost always be a string:uri to a single context file, but might rarely be an array of links or context objects instead. This schema also allows direct mapping of terms to IRIs by using an object as an option within an array. 10 | 11 | This property must be one of the following types: 12 | 13 | * `string` 14 | * `array` 15 | 16 | ### `type` (JsonLdType, required) 17 | 18 | A type or an array of types that the Blockchain Certificate object represents. The first or only item should be ‘BlockchainCertificate’, and any others should each be an IRI (usually a URL) corresponding to a definition of the type itself. In almost all cases, there will be only one type: ‘BlockchainCertificate’ 19 | 20 | This property must be one of the following types: 21 | 22 | * `string` 23 | * `array` 24 | 25 | ### `document` (CertificateDocument, required) 26 | 27 | [CertificateDocument](certificate-document.html) 28 | 29 | ### `receipt` (BlockchainReceipt, required) 30 | 31 | [BlockchainReceipt](receipt.html) 32 | -------------------------------------------------------------------------------- /docs/merkleProofSignatureExtension_schema.md: -------------------------------------------------------------------------------- 1 | ## MerkleProof2017 schema 2 | 3 | An extension that allows an issuer to issue an Open Badge on the blockchain and provide proof of inclusion in a blockchain transaction. This uses [Merkle Proof Signature Suite 2017](https://w3c-dvcg.github.io/lds-merkleproof2017/) 4 | 5 | This signature scheme is used along with the OBI verification extension type `MerkleProofVerification2017`. 6 | 7 | The schema defines the following properties: 8 | 9 | ### `type` (JsonLdType, required) 10 | 11 | ### `merkleRoot` (string, required) 12 | 13 | ### `targetHash` (string, required) 14 | 15 | ### `proof` (array, required) 16 | 17 | The object is an array with all elements of the type `object`. 18 | 19 | The array object has the following properties: 20 | 21 | #### `right` (string) 22 | 23 | #### `left` (string) 24 | 25 | ### `anchors` (array, required) 26 | 27 | The object is an array with all elements of the type `object`. 28 | 29 | The array object has the following properties: 30 | 31 | #### `sourceId` (string) 32 | 33 | #### `type` (string) 34 | 35 | #### `chain` (string) 36 | 37 | Chain is an optional field introduced by Blockcerts to help during verification. Current supported values are: 38 | 39 | - bitcoinMainnet 40 | - bitcoinTestnet 41 | - bitcoinRegtest 42 | - ethereumMainnet 43 | - ethereumRopsten 44 | - ethereumTestnet 45 | - mockchain 46 | 47 | 48 | --- 49 | 50 | # Sub Schemas 51 | 52 | The schema defines the following additional types: 53 | 54 | ## `JsonLdType` 55 | 56 | A type or an array of types defined in a JSON-LD context file. 57 | 58 | This property must be one of the following types: 59 | 60 | * `string` 61 | * `array` -------------------------------------------------------------------------------- /docs/open-badges.md: -------------------------------------------------------------------------------- 1 | ## Open Badges JSON LD Context 2 | 3 | { 4 | "@context": [ 5 | "https://w3id.org/openbadges/legacy-v1", 6 | { 7 | "id": "@id", 8 | "type": "@type", 9 | 10 | "obi": "https://w3id.org/openbadges#", 11 | "extensions": "https://w3id.org/openbadges/extensions#", 12 | "validation": "obi:validation", 13 | 14 | "xsd": "http://www.w3.org/2001/XMLSchema#", 15 | "schema": "http://schema.org/", 16 | "sec": "https://w3id.org/security#", 17 | 18 | "Assertion": "obi:Assertion", 19 | "BadgeClass": "obi:BadgeClass", 20 | "Issuer": "obi:Issuer", 21 | "Extension": "obi:Extension", 22 | "hosted": "obi:HostedBadge", 23 | "signed": "obi:SignedBadge", 24 | "TypeValidation": "obi:TypeValidation", 25 | "FrameValidation": "obi:FrameValidation", 26 | 27 | "name": { "@id": "schema:name" }, 28 | "description": { "@id": "schema:description" }, 29 | "url": { "@id": "schema:url", "@type": "@id" }, 30 | "image": { "@id": "schema:image", "@type": "@id" }, 31 | 32 | "uid": { "@id": "obi:uid" }, 33 | "recipient": { "@id": "obi:recipient", "@type": "@id" }, 34 | "hashed": { "@id": "obi:hashed", "@type": "xsd:boolean" }, 35 | "salt": { "@id": "obi:salt" }, 36 | "identity": { "@id": "obi:identityHash" }, 37 | "issuedOn": { "@id": "obi:issueDate", "@type": "xsd:dateTime" }, 38 | "expires": { "@id": "sec:expiration", "@type": "xsd:dateTime" }, 39 | "evidence": { "@id": "obi:evidence", "@type": "@id" }, 40 | "verify": { "@id": "obi:verify", "@type": "@id" }, 41 | 42 | "badge": { "@id": "obi:badge", "@type": "@id" }, 43 | "criteria": { "@id": "obi:criteria", "@type": "@id" }, 44 | "tags": { "@id": "schema:keywords" }, 45 | "alignment": { "@id": "obi:alignment", "@type": "@id" }, 46 | 47 | "issuer": { "@id": "obi:issuer", "@type": "@id" }, 48 | "email": "schema:email", 49 | "revocationList": { "@id": "obi:revocationList", "@type": "@id" }, 50 | 51 | "validatesType": "obi:validatesType", 52 | "validationSchema": "obi:validationSchema", 53 | "validationFrame": "obi:validationFrame" 54 | }], 55 | 56 | "validation": [ 57 | { 58 | "type": "TypeValidation", 59 | "validatesType": "Assertion", 60 | "validationSchema": "https://openbadgespec.org/v1/schema/assertion.json" 61 | }, 62 | { 63 | "type": "TypeValidation", 64 | "validatesType": "BadgeClass", 65 | "validationSchema": "https://openbadgespec.org/v1/schema/badgeclass.json" 66 | }, 67 | { 68 | "type": "TypeValidation", 69 | "validatesType": "Issuer", 70 | "validationSchema": "https://openbadgespec.org/v1/schema/issuer.json" 71 | }, 72 | { 73 | "type": "TypeValidation", 74 | "validatesType": "Extension", 75 | "validationSchema": "https://openbadgespec.org/v1/schema/extension.json" 76 | } 77 | ] 78 | } 79 | -------------------------------------------------------------------------------- /docs/open_badge_v2_extensions.md: -------------------------------------------------------------------------------- 1 | # Blockcerts Proposed Extensions to Open Badges V2 2 | 3 | The [Open Badges specification](https://www.imsglobal.org/sites/default/files/Badges/OBv2p0/index.html) is maintained by [IMS Global](http://www.imsglobal.org/). While developing Blockcerts, we created 4 Open Badge v2-compliant extensions. 2 of these are specific to blockchain verification; the other 2 are extensions we found useful. All are being offered as official Open Badge extensions to IMS Global Learning Consortium 4 | 5 | ## Summary of extensions 6 | 7 | - (Required for blockchain verification) blockchain verification type `MerkleProofVerification2017`, ideally as an enum added to the current verification options "hosted", "signed" 8 | - (Required for blockchain verification) `signature` proof as an Open Badge extension; defined by: 9 | - [W3C LD Signature Specification](https://w3c-dvcg.github.io/ld-signatures/) 10 | - [Merkle Proof Signature Suite](https://w3c-dvcg.github.io/lds-merkleproof2017/) 11 | - `recipientProfile` for identifying recipients 12 | - `RecipientProfile` extends the `Profile` type and adds `publicKey` for embedding a recipient's public key 13 | - `signatureLines` as a image/signer array, intended for display in the certificate 14 | 15 | ## Example 16 | 17 | Following is an example of a Blockcerts certificate. Note that this is fully OBv2 compliant. It uses the Open Badge `Extension` type to identify Open Badge extensions. These are marked in the example with `<` markers. 18 | 19 | ``` 20 | { 21 | "@context": ["https://w3id.org/openbadges/v2", "https://w3id.org/blockcerts/v2"], 22 | "type": "Assertion", 23 | "id": "urn:uuid:3bc1a96a-3501-46ed-8f75-49612bbac257", 24 | "issuedOn": "2017-07-20T09:33:47.490752+00:00", 25 | "recipient": { 26 | "hashed": false, 27 | "identity": "eularia@landroth.org", 28 | "type": "email" 29 | }, 30 | "recipientProfile": { <<<<<<<<<< 31 | "type": ["RecipientProfile", "Extension"], 32 | "name": "Eularia Landroth", 33 | "publicKey": "ecdsa-koblitz-pubkey:mtr98kany9G1XYNU74pRnfBQmaCg2FZLmc" 34 | }, 35 | "badge": { 36 | "type": "BadgeClass", 37 | "id": "urn:uuid:82a4c9f2-3588-457b-80ea-da695571b8fc", 38 | "name": "Certificate of Accomplishment", 39 | "image": "data:image/png;base64", 40 | "criteria": { 41 | "narrative": "Nibh iriure ei nam, modo ridens neglegentur mel eu. At his cibo mucius." 42 | }, 43 | "issuer": { 44 | "type": "Profile", 45 | "id": "https://www.blockcerts.org/samples/2.0/issuer-testnet.json", 46 | "name": "University of Learning", 47 | "email": "contact@issuer.org", 48 | "image": "data:image/png;base64,...", 49 | "url": "https://www.issuer.org", 50 | "revocationList": "https://www.blockcerts.org/samples/2.0/revocation-list-testnet.json" 51 | }, 52 | "signatureLines": [ <<<<<<<<<< 53 | { 54 | "type": ["SignatureLine", "Extension"], 55 | "name": "Your signature", 56 | "image": "data:image/png;base64,...", 57 | "jobTitle": "University Issuer" 58 | } 59 | ], 60 | "description": "Lorem ipsum dolor sit amet, mei docendi concludaturque ad, cu nec partem graece. Est aperiam consetetur cu, expetenda moderatius neglegentur ei nam, suas dolor laudem eam an." 61 | }, 62 | "verification": { <<<<<<<<<< 63 | "type": ["MerkleProofVerification2017", "Extension"], 64 | "publicKey": "ecdsa-koblitz-pubkey:msBCHdwaQ7N2ypBYupkp6uNxtr9Pg76imj" 65 | }, 66 | "signature": { 67 | "type": ["MerkleProof2017", "Extension"], <<<<<<<<<< 68 | "proof": [ 69 | { 70 | "right": "51b4e22ed024ec7f38dc68b0bf78c87eda525ab0896b75d2064bdb9fc60b2698" 71 | }, 72 | { 73 | "right": "61c56cca660b2e616d0bd62775e728f50275ae44adf12d1bfb9b9c507a14766b" 74 | } 75 | ], 76 | "merkleRoot": "3c9ee831b8705f2fbe09f8b3a92247eed88cdc90418c024924be668fdc92e781", 77 | "targetHash": "c65c6184e3d5a945ddb5437e93ea312411fd33aa1def22b0746d6ecd4aa30f20", 78 | "anchors": [ 79 | { 80 | "sourceId": "582733d7cef8035d87cecc9ebbe13b3a2f6cc52583fbcd2b9709f20a6b8b56b3", 81 | "type": "BTCOpReturn" 82 | } 83 | ] 84 | } 85 | } 86 | ``` 87 | 88 | ## Considerations for adopting as official Open Badge extensions 89 | 90 | - The current extension type/term names are not assumed to be final; it's expected that we will iterate on them during Open Badges review 91 | - Signature lines are currently defined in the `badge` type instead of the `assertion` type. I understand that this should likely move to `assertion` per OB extension best practices 92 | - The prefix `ecdsa-koblitz-pubkey:` 93 | - This is not final and is being Digital Verification subgroup of the W3C Credentials CG 94 | - The problem was that examples like this `ecdsa-koblitz-pubkey:msBCHdwaQ7N2ypBYupkp6uNxtr9Pg76imj` are not quite correct 95 | - The value right of the colon is a base58 encoded ecdsa koblitz public key hash 96 | - Currently the approach used by others in the community is to keep the `ecdsa-koblitz-pubkey:` and actually list the public key (not the hash) 97 | - The problem is readability (e.g. bitcoin addresses vs longer public keys) 98 | - Another option would be to invent a new prefix 99 | - Alternately, a more forward looking approach would be to use (or reserve) DIDs (Decentralized Identifiers) for this purpose. 100 | - Are there any special considerations in using the 2017 Merkle Proof Signature Suite from the W3C? 101 | - How do we integrate Blockcerts verification into the OB verifier? 102 | - How do we add the blockchain/blockcerts verification "type" (i.e. signed/hosted/...) 103 | 104 | ## Extension schemas and context 105 | 106 | ### Json-ld context 107 | 108 | The Json-ld context is listed in the context array of a blockcert. It defines these extension terms. See [https://w3id.org/blockcerts/v2](https://w3id.org/blockcerts/v2) 109 | 110 | ### Json schemas 111 | 112 | - MerkleProofVerification2017 is proposed as a new type enum to the current set of verification types 113 | - [Merkle Proof Signature Schema](https://github.com/blockchain-certificates/cert-schema/blob/master/docs/merkleProofSignatureExtension_schema.md) 114 | - [Recipient Profile Schema](https://github.com/blockchain-certificates/cert-schema/blob/master/docs/recipientProfileExtension_schema.md) 115 | - [Signature Line Schema](https://github.com/blockchain-certificates/cert-schema/blob/master/docs/signatureLineExtension_schema.md) 116 | 117 | -------------------------------------------------------------------------------- /docs/receipt.md: -------------------------------------------------------------------------------- 1 | ## Blockchain Receipt 2 | 3 | 4 | Provides evidence of the certificate on the blockchain, using the chainpoint v2 standard 5 | 6 | The schema defines the following properties: 7 | 8 | ### `@context` (string, required) 9 | 10 | This should always be chainpoint v2 JSON LD context 11 | 12 | Additional restrictions: 13 | 14 | * Regex pattern: `https://w3id.org/chainpoint/v2` 15 | 16 | ### `type` (string) 17 | 18 | type of hash. Currently the only supported hash type is SHA256, with chainpoint type ChainpointSHA256v2. 19 | 20 | Additional restrictions: 21 | 22 | * Regex pattern: `ChainpointSHA256v2` 23 | 24 | ### `targetHash` (string, required) 25 | 26 | hash of item being verified. Currently the only supported hash type is SHA256, and the targetHash format is validated accordingly. 27 | 28 | Additional restrictions: 29 | 30 | * Regex pattern: `[A-Fa-f0-9]{64}` 31 | 32 | ### `merkleRoot` (string, required) 33 | 34 | Merkle root value – this is anchored to the blockchain. Currently the only supported hash type is SHA256, and merkleRoot format is validated accordingly. 35 | 36 | Additional restrictions: 37 | 38 | * Regex pattern: `[A-Fa-f0-9]{64}` 39 | 40 | ### `proof` (array, required) 41 | 42 | how to walk the Merkle tree from the target item to the Merkle root 43 | 44 | The object is an array with all elements of the type `object`. 45 | 46 | The array object has the following properties: 47 | 48 | `left` (string) 49 | 50 | value of left neighbor to combine into parent hash. Currently the only supported hash type is SHA256, and this value format is validated accordingly. 51 | 52 | Additional restrictions: 53 | 54 | * Regex pattern: `[A-Fa-f0-9]{64}` 55 | 56 | `right` (string) 57 | 58 | value of right neighbor to combine into parent hash. Currently the only supported hash type is SHA256, and this value format is validated accordingly. 59 | 60 | Additional restrictions: 61 | 62 | * Regex pattern: `[A-Fa-f0-9]{64}` 63 | 64 | ### `anchors` (array, required) 65 | 66 | How the proof is anchored to the blockchain. 67 | 68 | The object is an array with all elements of the type `object`. 69 | 70 | The array object has the following properties: 71 | 72 | `type` (string) 73 | 74 | Type of anchor, e.g. BTCOpReturn. Currently the only supported value is BTCOpReturn. 75 | 76 | Additional restrictions: 77 | 78 | * Regex pattern: `BTCOpReturn` 79 | 80 | `sourceId` (string, required) 81 | 82 | How to lookup the proof on the blockchain. Currently this is expected to be the (value of the) Bitcoin transaction id, and this value format is validated accordingly 83 | 84 | Additional restrictions: 85 | 86 | * Regex pattern: `[A-Fa-f0-9]{64}` 87 | -------------------------------------------------------------------------------- /docs/recipientProfileExtension_schema.md: -------------------------------------------------------------------------------- 1 | ## RecipientProfile schema 2 | 3 | A Blockcerts extension allowing inclusion of additional recipient details, including recipient publicKey and name. Inclusion of the recipient publicKey allows the recipient to make a strong claim of ownership over the key, and hence the badge being awarded. In the future, publicKey will be deprecated in favor of a decentralized id (DID) in the `id` field. 4 | 5 | The schema defines the following properties: 6 | 7 | ### `id` (string) 8 | 9 | reserved for future use as DID 10 | 11 | ### `name` (string) 12 | 13 | Name of recipient, [http://schema.org/name](http://schema.org/name) 14 | 15 | ### `publicKey` (string) 16 | 17 | In Blockcerts `publicKey` IRIs are typically represented with a `:` prefix. For Bitcoin transactions, this would be the recipient public Bitcoin address prefixed with `ecdsa-koblitz-pubkey:`; e.g. `ecdsa-koblitz-pubkey:14RZvYazz9H2DC2skBfpPVxax54g4yabxe` 18 | 19 | Additional restrictions: 20 | 21 | * Format: `uri` -------------------------------------------------------------------------------- /docs/schema-2.md: -------------------------------------------------------------------------------- 1 | ## Assertion schema 2 | 3 | Blockcerts 2.0 Assertion schema. Extends Open Badges v2.0 schema: [https://w3id.org/openbadges#Assertion](https://w3id.org/openbadges#Assertion) 4 | 5 | The schema defines the following properties: 6 | 7 | ### `id` (string, required) 8 | 9 | Defined by `id` property in https://w3id.org/openbadges#Assertion. This may be an HTTP IRI, but only if the issuer plans to host the assertions on a long-term basis, or (at least) until their expiration. Otherwise it is recommended to use a `urn:uuid:`-formatted IRI. 10 | 11 | ### `type` (JsonLdType, required) 12 | 13 | Defined by `type` property of https://w3id.org/openbadges#Assertion 14 | 15 | ### `recipient` (IdentityObject, required) 16 | 17 | Defined by `recipient` property of https://w3id.org/openbadges#Assertion, with Blockcerts extensions for recipient proof of ownership. 18 | 19 | ### `badge` (BadgeClass, required) 20 | 21 | Defined by `badge` property of https://w3id.org/openbadges#Assertion, with Blockcerts extensions for (display) signature images. 22 | 23 | ### `verification` (VerificationObject, required) 24 | 25 | Defined by `verification` property of https://w3id.org/openbadges#Assertion, with Blockcerts extensions for verification of badges on a blockchain. 26 | 27 | ### `issuedOn` (DateTime, required) 28 | 29 | Defined by `issuedOn` property of https://w3id.org/openbadges#Assertion 30 | 31 | ### `image` (ImageUri) 32 | 33 | Defined by `image` property of https://w3id.org/openbadges#Assertion 34 | 35 | ### `evidence` (string) 36 | 37 | Defined by `evidence` property of https://w3id.org/openbadges#Assertion 38 | 39 | ### `narrative` (string) 40 | 41 | Defined by `narrative` property of https://w3id.org/openbadges#Assertion 42 | 43 | ### `expires` (DateTime) 44 | 45 | Defined by `expires` property of https://w3id.org/openbadges#Assertion 46 | 47 | ### `recipientProfile` (RecipientProfile) 48 | 49 | ### `signature` (MerkleProof2017) 50 | 51 | 52 | 53 | ## Sub Schemas 54 | 55 | The schema defines the following additional types: 56 | 57 | ### `JsonLdContext` (undefined) 58 | 59 | A link to a valid JSON-LD context, or array of JSON-LD contexts 60 | 61 | This property must be one of the following types: 62 | 63 | * `string` 64 | * `array` 65 | 66 | ### `JsonLdType` (undefined) 67 | 68 | A type or an array of types defined in a referenced JSON-LD context. 69 | 70 | This property must be one of the following types: 71 | 72 | * `string` 73 | * `array` 74 | 75 | ## `DateTime` (string) 76 | # 77 | Open Badges must express timestamps as strings compatible with ISO 8601 guidelines, including the time and a time zone indicator. It is recommended to publish all timestamps in UTC. Previous versions of Open Badges allowed Unix timestamps as integers. Open Badges v2.0 requires string ISO 8601 values with time zone indicators. For example, 2016-12-31T23:59:59+00:00 is a valid ISO 8601 timestamp. It contains the year, month, day, T separator, hour number 0-23, minute, optional seconds and decimal microsecond, and a time zone indicator (+/- an offset from UTC or the Z designator for UTC). 78 | 79 | ### `HashString` (string) 80 | 81 | Open Badges SHA-256 Hash 82 | 83 | ### `IdentityObject` (object) 84 | 85 | From https://w3id.org/openbadges#IdentityObject. 86 | 87 | Properties of the `IdentityObject` object: 88 | 89 | #### `identity` (, required) 90 | 91 | Defined by `identity` property of https://w3id.org/openbadges#IdentityObject 92 | 93 | The object must be one of the following types: 94 | 95 | * `HashString` 96 | * `undefined` 97 | 98 | #### `type` (string, enum, required) 99 | 100 | Defined by `type` property of https://w3id.org/openbadges#IdentityObject 101 | 102 | This element must be one of the following enum values: 103 | 104 | * `email` 105 | 106 | #### `hashed` (boolean, required) 107 | 108 | Defined by `hashed` property of https://w3id.org/openbadges#IdentityObject 109 | 110 | #### `salt` 111 | 112 | Defined by `salt` property of https://w3id.org/openbadges#IdentityObject 113 | 114 | ### `VerificationObject` (object) 115 | 116 | From https://w3id.org/openbadges#VerificationObject, with extensions for Blockcerts verification 117 | 118 | Properties of the `VerificationObject` object: 119 | 120 | #### `type` (JsonLdType, required) 121 | 122 | Defined by `type` property of https://w3id.org/openbadges#VerificationObject. Blockcerts extension: this should contain the entry `MerkleProofVerification2017` 123 | 124 | #### `publicKey` (string) 125 | 126 | Blockcerts extension: the expected blockchain address for the signer of the transaction containing the merkle proof. In Blockcerts `publicKey`s are typically represented with a `:` prefix. For Bitcoin transactions, this would be the issuer public Bitcoin address prefixed with `ecdsa-koblitz-pubkey:`; e.g. `ecdsa-koblitz-pubkey:14RZvYazz9H2DC2skBfpPVxax54g4yabxe` 127 | 128 | ### `ImageUri` (string) 129 | 130 | An image representative of the entity. In Blockcerts this is typically a data URI (https://en.wikipedia.org/wiki/Data_URI_scheme) embedded as a base-64 encoded PNG image, but it may also be a URI where the image may be found. 131 | 132 | ### `AlignmentObject` (object) 133 | 134 | From https://w3id.org/openbadges#AlignmentObject 135 | 136 | Properties of the `AlignmentObject` object: 137 | 138 | #### `targetName` (string, required) 139 | 140 | Defined by `targetName` property of https://w3id.org/openbadges#AlignmentObject 141 | 142 | ### `targetUrl` (string, required) 143 | 144 | Defined by `targetUrl` property of https://w3id.org/openbadges#AlignmentObject 145 | 146 | #### `targetDescription` (string) 147 | 148 | Defined by `targetDescription` property of https://w3id.org/openbadges#AlignmentObject 149 | 150 | ### `AlignmentArray` (array) 151 | 152 | List of objects describing which objectives or educational standards this badge aligns to, if any. 153 | 154 | ### `TagsArray` (array) 155 | 156 | List of tags that describe the type of achievement. 157 | 158 | ### `SignatureLine` (undefined) 159 | 160 | ### `RecipientProfile` (undefined) 161 | 162 | ### `MerkleProof2017` (undefined) 163 | 164 | ### `BadgeClass` (object) 165 | 166 | From https://w3id.org/openbadges#BadgeClass 167 | 168 | Properties of the `BadgeClass` object: 169 | 170 | #### `id` (string, required) 171 | 172 | Defined by `id` property of https://w3id.org/openbadges#BadgeClass. This field is now required in V2. This may be an HTTP IRI, but only if the issuer plans to host the BadgeClass definitions on a long-term basis, or (at least) until expiration of certificates referencing this BadgeClass. Otherwise it is recommended to use a `urn:uuid:`-formatted IRI. 173 | 174 | #### `type` (JsonLdType) 175 | 176 | Defined by `type` property of https://w3id.org/openbadges#BadgeClass 177 | 178 | #### `name` (string, required) 179 | 180 | Defined by `name` property of https://w3id.org/openbadges#BadgeClass 181 | 182 | #### `subtitle` (string) 183 | 184 | Blockcerts extension: optional subtitle of the certificate 185 | 186 | #### `description` (string, required) 187 | 188 | Defined by `description` property of https://w3id.org/openbadges#BadgeClass 189 | 190 | #### `image` (ImageUri, required) 191 | 192 | Defined by `image` property of https://w3id.org/openbadges#BadgeClass 193 | 194 | #### `criteria` (object, required) 195 | 196 | Defined by `criteria` property of https://w3id.org/openbadges#BadgeClass. This field is required in Open Badges. If migrating from an earlier version, a quick change is to reuse the `description` field 197 | 198 | #### `issuer` (Profile, required) 199 | 200 | Defined by `issuer` property of https://w3id.org/openbadges#BadgeClass, with Blockcerts extensions for blockchain verification of badges. 201 | 202 | #### `alignment` (AlignmentArray) 203 | 204 | Defined by `alignment` property of https://w3id.org/openbadges#BadgeClass 205 | 206 | #### `tags` (TagsArray) 207 | 208 | Defined by `tags` property of https://w3id.org/openbadges#BadgeClass 209 | 210 | #### `signatureLines` 211 | 212 | Blockcerts extension: array of signature lines for display. 213 | 214 | ### `Profile` (undefined) 215 | 216 | Defined by https://w3id.org/openbadges#Profile. This type is used in certificates, and in the issuer-hosted identification page. The minimal set of properties required in the certificate are `id` and `type`. In this case, additional issuer-identification properties are assumed to be available at the issuer-hosted identification page. 217 | 218 | #### `id` (string, required) 219 | 220 | Defined by `id` property of https://w3id.org/openbadges#Profile 221 | 222 | #### `type` (JsonLdType, required) 223 | 224 | Defined by `type` property of https://w3id.org/openbadges#Profile 225 | 226 | #### `name` (string) 227 | 228 | Defined by `name` property of https://w3id.org/openbadges#Profile 229 | 230 | #### `url` (string) 231 | 232 | Defined by `url` property of https://w3id.org/openbadges#Profile 233 | 234 | #### `telephone` (string) 235 | 236 | Defined by `telephone` property of https://w3id.org/openbadges#Profile 237 | 238 | #### `description` (string) 239 | 240 | Defined by `description` property of https://w3id.org/openbadges#Profile 241 | 242 | #### `image` (ImageUri) 243 | 244 | Defined by `image` property of https://w3id.org/openbadges#Profile 245 | 246 | #### `email` (string) 247 | 248 | Defined by `email` property of https://w3id.org/openbadges#Profile 249 | 250 | #### `revocationList` 251 | 252 | Defined by `revocationList` property of https://w3id.org/openbadges#Profile. If embedded in a Blockcert and the issuer-hosted Profile, the value in the Blockcert should take preference. -------------------------------------------------------------------------------- /docs/schema.md: -------------------------------------------------------------------------------- 1 | ## Assertion schema 2 | 3 | Blockcerts 2.0 Assertion schema. Extends Open Badges v2.0 schema: [https://w3id.org/openbadges#Assertion](https://w3id.org/openbadges#Assertion) 4 | 5 | The schema defines the following properties: 6 | 7 | ### `id` (string, required) 8 | 9 | Defined by `id` property in [https://w3id.org/openbadges#Assertion](https://w3id.org/openbadges#Assertion). This may be an HTTP IRI, but only if the issuer plans to host the assertions on a long-term basis, or (at least) until their expiration. Otherwise it is recommended to use a `urn:uuid:`-formatted IRI. 10 | 11 | The object may be any of the following types: 12 | 13 | * `string` 14 | * Pattern: `^urn:uuid:` 15 | * `string` 16 | * Format: `uri` 17 | 18 | ### `type` (JsonLdType, required) 19 | 20 | Defined by `type` property of [https://w3id.org/openbadges#Assertion](https://w3id.org/openbadges#Assertion) 21 | 22 | ### `recipient` (IdentityObject, required) 23 | 24 | Defined by `recipient` property of [https://w3id.org/openbadges#Assertion](https://w3id.org/openbadges#Assertion), with Blockcerts extensions for recipient proof of ownership. 25 | 26 | ### `badge` (BadgeClass, required) 27 | 28 | Defined by `badge` property of [https://w3id.org/openbadges#Assertion](https://w3id.org/openbadges#Assertion), with Blockcerts extensions for (display) signature images. 29 | 30 | ### `verification` (VerificationObject, required) 31 | 32 | Defined by `verification` property of [https://w3id.org/openbadges#Assertion](https://w3id.org/openbadges#Assertion), with Blockcerts extensions for verification of badges on a blockchain. 33 | 34 | ### `issuedOn` (DateTime, required) 35 | 36 | Defined by `issuedOn` property of [https://w3id.org/openbadges#Assertion](https://w3id.org/openbadges#Assertion) 37 | 38 | ### `image` (ImageUri) 39 | 40 | Defined by `image` property of [https://w3id.org/openbadges#Assertion](https://w3id.org/openbadges#Assertion) 41 | 42 | ### `evidence` (string) 43 | 44 | Defined by `evidence` property of [https://w3id.org/openbadges#Assertion](https://w3id.org/openbadges#Assertion) 45 | 46 | Additional restrictions: 47 | 48 | * Format: `uri` 49 | 50 | ### `narrative` (string) 51 | 52 | Defined by `narrative` property of [https://w3id.org/openbadges#Assertion](https://w3id.org/openbadges#Assertion) 53 | 54 | ### `expires` (DateTime) 55 | 56 | Defined by `expires` property of [https://w3id.org/openbadges#Assertion](https://w3id.org/openbadges#Assertion) 57 | 58 | ### `signature` (MerkleProof2017) 59 | 60 | Blockcerts extension [MerkleProof2017](merkleProofSignatureExtension_schema.html) 61 | 62 | 63 | --- 64 | 65 | # Sub Schemas 66 | 67 | The schema defines the following additional types: 68 | 69 | ## `JsonLdContext` 70 | 71 | A link to a valid JSON-LD context, or array of JSON-LD contexts 72 | 73 | This property must be one of the following types: 74 | 75 | * `string` 76 | * `array` 77 | 78 | ## `JsonLdType` 79 | 80 | A type or an array of types defined in a referenced JSON-LD context. 81 | 82 | This property must be one of the following types: 83 | 84 | * `string` 85 | * `array` 86 | 87 | ## `ISODateTime` (string) 88 | 89 | ISO 8601 date format string `yyyy-MM-dd'T'HH:mm:ss.SSS` with optional `.SSS` milliseconds 90 | 91 | ## `UNIXTimeStamp` (integer) 92 | 93 | 10-digit UNIX timestamp, epoch time 94 | 95 | ## `DateTime` 96 | 97 | This property may be any of the following types: 98 | 99 | * `ISODateTime` 100 | * `UNIXTimeStamp` 101 | 102 | ## `HashString` (string) 103 | 104 | Open Badges SHA-256 Hash 105 | 106 | ## `IdentityObject` (object) 107 | 108 | From [https://w3id.org/openbadges#IdentityObject](https://w3id.org/openbadges#IdentityObject), with extensions for recipient profile. 109 | 110 | Properties of the `IdentityObject` object: 111 | 112 | ### `identity` (object, required) 113 | 114 | Defined by `identity` property of [https://w3id.org/openbadges#IdentityObject](https://w3id.org/openbadges#IdentityObject) 115 | 116 | ### `type` (string, enum, required) 117 | 118 | Defined by `type` property of [https://w3id.org/openbadges#IdentityObject](https://w3id.org/openbadges#IdentityObject) 119 | 120 | This element must be one of the following enum values: 121 | 122 | * `email` 123 | 124 | ### `hashed` (boolean, required) 125 | 126 | Defined by `hashed` property of [https://w3id.org/openbadges#IdentityObject](https://w3id.org/openbadges#IdentityObject) 127 | 128 | ### `salt` (object) 129 | 130 | Defined by `salt` property of [https://w3id.org/openbadges#IdentityObject](https://w3id.org/openbadges#IdentityObject) 131 | 132 | ### `recipientProfile` (RecipientProfile) 133 | 134 | Blockcerts extension: [RecipientProfile](recipientProfileExtension_schema.html), allowing the recipient to prove ownership. 135 | 136 | ## `VerificationObject` (object) 137 | 138 | From [https://w3id.org/openbadges#VerificationObject](https://w3id.org/openbadges#VerificationObject), with extensions for Blockcerts verification 139 | 140 | Properties of the `VerificationObject` object: 141 | 142 | ### `type` (JsonLdType, required) 143 | 144 | Defined by `type` property of [https://w3id.org/openbadges#VerificationObject](https://w3id.org/openbadges#VerificationObject). Blockcerts extension: this should contain the entry `MerkleProofVerification2017` 145 | 146 | ### `creator` (string) 147 | 148 | Blockcerts extension: the expected blockchain address for the signer of the transaction containing the merkle proof. In Blockcerts `creator` IRIs are typically represented with a `:` prefix. For Bitcoin transactions, this would be the issuer public Bitcoin address prefixed with `ecdsa-koblitz-pubkey:`; e.g. `ecdsa-koblitz-pubkey:14RZvYazz9H2DC2skBfpPVxax54g4yabxe` 149 | 150 | The object may be any of the following types: 151 | 152 | * `string` 153 | * Pattern: `^ecdsa-koblitz-pubkey:` 154 | * Description: Issuer public key or blockchain address with `:` prefix. For Bitcoin transactions, this would be the issuer public address prefixed with `ecdsa-koblitz-pubkey:`. Example: `ecdsa-koblitz-pubkey:14RZvYazz9H2DC2skBfpPVxax54g4yabxe` 155 | * `string` 156 | * Format: `uri` 157 | 158 | ### `verificationProperty` (object) 159 | 160 | Defined by `verificationProperty` property of [https://w3id.org/openbadges#VerificationObject](https://w3id.org/openbadges#VerificationObject) 161 | 162 | ### `startsWith` (string) 163 | 164 | Defined by `startsWith` property of [https://w3id.org/openbadges#VerificationObject](https://w3id.org/openbadges#VerificationObject) 165 | 166 | Additional restrictions: 167 | 168 | * Format: `uri` 169 | 170 | ### `allowedOrigins` (string) 171 | 172 | Defined by `allowedOrigins` property of [https://w3id.org/openbadges#VerificationObject](https://w3id.org/openbadges#VerificationObject) 173 | 174 | Additional restrictions: 175 | 176 | * Format: `uri` 177 | 178 | ## `ImageUri` (string) 179 | 180 | An image representative of the entity. In Blockcerts this is typically a data URI ([https://en.wikipedia.org/wiki/Data_URI_scheme](https://en.wikipedia.org/wiki/Data_URI_scheme)) embedded as a base-64 encoded PNG image, but it may also be a URI where the image may be found. 181 | 182 | This property may be any of the following types: 183 | 184 | * `string` 185 | * Pattern: `^data:` 186 | * `string` 187 | * Format: `uri` 188 | 189 | ## `AlignmentObject` (object) 190 | 191 | From [https://w3id.org/openbadges#AlignmentObject](https://w3id.org/openbadges#AlignmentObject) 192 | 193 | Properties of the `AlignmentObject` object: 194 | 195 | ### `targetName` (string, required) 196 | 197 | Defined by `targetName` property of [https://w3id.org/openbadges#AlignmentObject](https://w3id.org/openbadges#AlignmentObject) 198 | 199 | ### `targetUrl` (string, required) 200 | 201 | Defined by `targetUrl` property of [https://w3id.org/openbadges#AlignmentObject](https://w3id.org/openbadges#AlignmentObject) 202 | 203 | Additional restrictions: 204 | 205 | * Format: `uri` 206 | 207 | ### `targetDescription` (string) 208 | 209 | Defined by `targetDescription` property of [https://w3id.org/openbadges#AlignmentObject](https://w3id.org/openbadges#AlignmentObject) 210 | 211 | ## `BadgeClass` (object) 212 | 213 | From [https://w3id.org/openbadges#BadgeClass](https://w3id.org/openbadges#BadgeClass) 214 | 215 | Properties of the `BadgeClass` object: 216 | 217 | ### `id` (string) 218 | 219 | Defined by `id` property of [https://w3id.org/openbadges#BadgeClass](https://w3id.org/openbadges#BadgeClass). This field is required in Open Badges but currently optional in Blockcerts for compatibility. This may be an HTTP IRI, but only if the issuer plans to host the BadgeClass definitions on a long-term basis, or (at least) until expiration of certificates referencing this BadgeClass. Otherwise it is recommended to use a `urn:uuid:`-formatted IRI. 220 | 221 | Additional restrictions: 222 | 223 | * Format: `uri` 224 | 225 | ### `type` (JsonLdType) 226 | 227 | Defined by `type` property of [https://w3id.org/openbadges#BadgeClass](https://w3id.org/openbadges#BadgeClass) 228 | 229 | ### `name` (string, required) 230 | 231 | Defined by `name` property of [https://w3id.org/openbadges#BadgeClass](https://w3id.org/openbadges#BadgeClass) 232 | 233 | ### `subtitle` (string) 234 | 235 | Blockcerts extension: optional subtitle of the certificate 236 | 237 | ### `description` (string, required) 238 | 239 | Defined by `description` property of [https://w3id.org/openbadges#BadgeClass](https://w3id.org/openbadges#BadgeClass) 240 | 241 | ### `image` (ImageUri, required) 242 | 243 | Defined by `image` property of [https://w3id.org/openbadges#BadgeClass](https://w3id.org/openbadges#BadgeClass) 244 | 245 | ### `criteria` (object) 246 | 247 | Defined by `criteria` property of [https://w3id.org/openbadges#BadgeClass](https://w3id.org/openbadges#BadgeClass). This field is required in Open Badges, currently optional in Blockcerts for compatibility. 248 | 249 | ### `issuer` (Profile, required) 250 | 251 | Defined by `issuer` property of [https://w3id.org/openbadges#BadgeClass](https://w3id.org/openbadges#BadgeClass), with Blockcerts extensions for blockchain verification of badges. 252 | 253 | [Profile schema](issuer_schema.html) 254 | 255 | 256 | ### `alignment` (AlignmentArray) 257 | 258 | Defined by `alignment` property of [https://w3id.org/openbadges#BadgeClass](https://w3id.org/openbadges#BadgeClass) 259 | 260 | ### `tags` (TagsArray) 261 | 262 | Defined by `tags` property of [https://w3id.org/openbadges#BadgeClass](https://w3id.org/openbadges#BadgeClass) 263 | 264 | ### `signatureLines` (object) 265 | 266 | Blockcerts extension: array of [SignatureLine](signatureLineExtension_schema.html), for display in the certificate. 267 | 268 | -------------------------------------------------------------------------------- /docs/signatureLineExtension_schema.md: -------------------------------------------------------------------------------- 1 | ## SignatureLine schema 2 | 3 | An extension that allows issuers to add signature lines to the visual representation of the badge. This is not part of the cryptographic proof; it is for display purposes only. 4 | 5 | The schema defines the following properties: 6 | 7 | ### `image` (ImageUri, required) 8 | 9 | ### `jobTitle` (string) 10 | 11 | Job title of signer, [http://schema.org/jobTitle](http://schema.org/jobTitle) 12 | 13 | ### `name` (string) 14 | 15 | Full name of signer, [http://schema.org/name](http://schema.org/name) 16 | 17 | --- 18 | 19 | # Sub Schemas 20 | 21 | The schema defines the following additional types: 22 | 23 | ## `ImageUri` 24 | 25 | This property may be any of the following types: 26 | 27 | * `string` 28 | * Pattern: `data:image/png;base64,` 29 | * Description: An image representative of the entity. In Blockcerts this is typically a data URI ([https://en.wikipedia.org/wiki/Data_URI_scheme](https://en.wikipedia.org/wiki/Data_URI_scheme)) embedded as a base-64 encoded PNG image, but it may also be a URI where the image may be found. 30 | * `string` 31 | * Format: `uri` 32 | * Description: IRI (typically HTTP) representing this signature image. -------------------------------------------------------------------------------- /docs/v1_x_schema.md: -------------------------------------------------------------------------------- 1 | ## Schemas 2 | 3 | Blockchain Certificate schemas extend those of [Open Badges](https://openbadgespec.org/). As with Open Badges, we've provided both a JSON-LD context and JSON schema. The purpose of the JSON-LD context is to map types to Internationalized Resource Identifiers (IRIs), providing semantic context for data. The JSON Schema is used for syntactic validation. 4 | 5 | We are working closely with the Open Badges team to bring our schemas up to the OBI v2 spec. 6 | 7 | * [Blockchain Certificates JSON LD Context](json-context.md) 8 | * [Blockchain Certificate JSON Schema](json-schema.md) (components below) 9 | * [Certificate Document](certificate-document.md) 10 | * [Assertion](assertion-schema.md) 11 | * [Certificate](certificate-schema.md) 12 | * [Issuer](issuer.md) 13 | * [Blockchain Receipt](receipt.md) 14 | * [Issuer Identity JSON Schema](issuer-id.md) 15 | 16 | ### Example 17 | 18 | { 19 | "@context": "https://w3id.org/blockcerts/v1", 20 | "type": "BlockchainCertificate", 21 | "document": { 22 | "type": "CertificateDocument", 23 | "assertion": { 24 | "type": "Assertion", 25 | "evidence": "", 26 | "id": "http://www.theissuer.edu/fb9e6259-f3ee-438a-b98f-a24f54187af8", 27 | "image:signature": "data:image/png;base64,", 28 | "issuedOn": "2016-05-26T12:00:00Z", 29 | "uid": "fb9e6259-f3ee-438a-b98f-a24f54187af8" 30 | }, 31 | "certificate": { 32 | "type": "Certificate", 33 | "description": "Certificate description", 34 | "id": "https://www.theissuer.edu/criteria/2016/05/certificate-type.json", 35 | "image": "data:image/png;base64,", 36 | "issuer": { 37 | "type": "Issuer", 38 | "email": "issuer@theissuer.edu", 39 | "id": "https://www.theissuer.edu/issuer/the-issuer.json", 40 | "image": "data:image/png;base64,", 41 | "name": "Issuing Institution", 42 | "url": "http://www.theissuer.edu" 43 | }, 44 | "subtitle": "2016", 45 | "name": "Certificate name" 46 | }, 47 | "recipient": { 48 | "familyName": "RecipientLastName", 49 | "givenName": "RecipientFirstName", 50 | "hashed": false, 51 | "identity": "recipient@domain.com", 52 | "publicKey": "1GCrFRozNVWCqTreV7ZoXudiotknoJeXaz", 53 | "type": "email" 54 | }, 55 | "signature": "IAhahreb77hgM9khBcWCSfwq0Qal/bzU9AzBSUMEDErTdExBRHsBH2dDmBa1NvR38wVGn70SPEglI0VIvUFc2AI=", 56 | "verify": { 57 | "attribute-signed": "uid", 58 | "signer": "https://www.theissuer.edu/keys/signing-public-key.asc", 59 | "type": "ECDSA(secp256k1)" 60 | } 61 | }, 62 | "receipt": { 63 | "@context": "https://w3id.org/chainpoint/v2", 64 | "type": "ChainpointSHA256v2", 65 | "targetHash": "3e23e8160039594a33894f6564e1b1348bbd7a0088d42c4acb73eeaed59c009d", 66 | "merkleRoot": "d71f8983ad4ee170f8129f1ebcdd7440be7798d8e1c80420bf11f1eced610dba", 67 | "proof": [ 68 | { 69 | "left": "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb" 70 | }, 71 | { 72 | "right": "bffe0b34dba16bc6fac17c08bac55d676cded5a4ade41fe2c9924a5dde8f3e5b" 73 | }, 74 | { 75 | "right": "3f79bb7b435b05321651daefd374cdc681dc06faa65e374e38337b88ca046dea" 76 | } 77 | ], 78 | "anchors": [ 79 | { 80 | "type": "BTCOpReturn", 81 | "sourceId": "b84a92f28cc9dbdc4cd51834f6595cf97f018b925167c299097754780d7dea09" 82 | } 83 | ] 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /examples/1.1/sample_unsigned_cert-1.1.json: -------------------------------------------------------------------------------- 1 | { 2 | "verify": { 3 | "signer": "https://www.theissuer.edu/keys/signing-public-key.asc", 4 | "attribute-signed": "uid", 5 | "type": "ECDSA(secp256k1)" 6 | }, 7 | "recipient": { 8 | "type": "email", 9 | "familyName": "RecipientLastName", 10 | "hashed": false, 11 | "givenName": "RecipientFirstName", 12 | "pubkey": "n1EduLzKsTL1pM8Roz9vEV16AQnBdg9JCx", 13 | "identity": "recipient@domain.com" 14 | }, 15 | "assertion": { 16 | "issuedOn": "2016-05-26T12:00:00.000000", 17 | "image:signature": "data:image/png;base64,", 18 | "id": "http://www.theissuer.edu/68656c6c6f636f6d7077ffff", 19 | "uid": "68656c6c6f636f6d7077ffff", 20 | "evidence": "" 21 | }, 22 | "certificate": { 23 | "subtitle": { 24 | "content": "2016", 25 | "display": false 26 | }, 27 | "description": "Certificate description", 28 | "title": "Certificate title", 29 | "image": "data:image/png;base64,", 30 | "id": "https://www.theissuer.edu/criteria/2016/05/certificate-type.json", 31 | "issuer": { 32 | "url": "http://www.theissuer.edu", 33 | "image": "data:image/png;base64,", 34 | "email": "issuer@theissuer.edu", 35 | "name": "Issuing Institution", 36 | "id": "https://www.theissuer.edu/issuer/the-issuer.json" 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/1.2/sample_invalid_cert-1.2.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": "https://w3id.org/blockcerts/v1", 3 | "type": "BlockchainCertificate", 4 | "document": { 5 | "type": "CertificateDocument", 6 | "assertion": { 7 | "type": "Assertion", 8 | "evidence": "", 9 | "id": "http://www.theissuer.edu/fb9e6259-f3ee-438a-b98f-a24f54187af8", 10 | "image:signature": "data:image/png;base64,", 11 | "issuedOn": "2016-05-26T12:00:00Z", 12 | "uid": "fb9e6259-f3ee-438a-b98f-a24f54187af8" 13 | }, 14 | "certificate": { 15 | "image": "data:image/png;base64,", 16 | "issuer": { 17 | "type": "Issuer", 18 | "email": "issuer@theissuer.edu", 19 | "id": "https://www.theissuer.edu/issuer/the-issuer.json", 20 | "image": "data:image/png;base64,", 21 | "name": "Issuing Institution", 22 | "url": "http://www.theissuer.edu" 23 | }, 24 | "subtitle": "2016", 25 | "name": "Certificate name" 26 | }, 27 | "recipient": { 28 | "familyName": "RecipientLastName", 29 | "givenName": "RecipientFirstName", 30 | "hashed": false, 31 | "identity": "recipient@domain.com", 32 | "publicKey": "1GCrFRozNVWCqTreV7ZoXudiotknoJeXaz", 33 | "type": "email" 34 | }, 35 | "signature": "IAhahreb77hgM9khBcWCSfwq0Qal/bzU9AzBSUMEDErTdExBRHsBH2dDmBa1NvR38wVGn70SPEglI0VIvUFc2AI=", 36 | "verify": { 37 | "attribute-signed": "uid", 38 | "type": "ECDSA(secp256k1)" 39 | } 40 | }, 41 | "receipt": { 42 | "@context": "https://w3id.org/chainpoint/v2", 43 | "type": "ChainpointSHA256v2", 44 | "targetHash": "3e23e8160039594a33894f6564e1b1348bbd7a0088d42c4acb73eeaed59c009d", 45 | "merkleRoot": "d71f8983ad4ee170f8129f1ebcdd7440be7798d8e1c80420bf11f1eced610dba", 46 | "proof": [ 47 | { 48 | "left": "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb" 49 | }, 50 | { 51 | "right": "bffe0b34dba16bc6fac17c08bac55d676cded5a4ade41fe2c9924a5dde8f3e5b" 52 | }, 53 | { 54 | "right": "3f79bb7b435b05321651daefd374cdc681dc06faa65e374e38337b88ca046dea" 55 | } 56 | ], 57 | "anchors": [ 58 | { 59 | "type": "BTCOpReturn", 60 | "sourceId": "b84a92f28cc9dbdc4cd51834f6595cf97f018b925167c299097754780d7dea09" 61 | } 62 | ] 63 | } 64 | } -------------------------------------------------------------------------------- /examples/1.2/sample_signed_cert-1.2.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": "https://w3id.org/blockcerts/v1", 3 | "type": "BlockchainCertificate", 4 | "document": { 5 | "type": "CertificateDocument", 6 | "assertion": { 7 | "type": "Assertion", 8 | "evidence": "", 9 | "id": "http://www.theissuer.edu/fb9e6259-f3ee-438a-b98f-a24f54187af8", 10 | "image:signature": "data:image/png;base64,", 11 | "issuedOn": "2016-05-26T12:00:00Z", 12 | "uid": "fb9e6259-f3ee-438a-b98f-a24f54187af8" 13 | }, 14 | "certificate": { 15 | "type": "Certificate", 16 | "description": "Certificate description", 17 | "image": "data:image/png;base64,", 18 | "issuer": { 19 | "type": "Issuer", 20 | "email": "issuer@theissuer.edu", 21 | "id": "https://www.theissuer.edu/issuer/the-issuer.json", 22 | "image": "data:image/png;base64,", 23 | "name": "Issuing Institution", 24 | "url": "http://www.theissuer.edu" 25 | }, 26 | "subtitle": "2016", 27 | "name": "Certificate name" 28 | }, 29 | "recipient": { 30 | "familyName": "RecipientLastName", 31 | "givenName": "RecipientFirstName", 32 | "hashed": false, 33 | "identity": "recipient@domain.com", 34 | "publicKey": "1GCrFRozNVWCqTreV7ZoXudiotknoJeXaz", 35 | "type": "email" 36 | }, 37 | "signature": "IAhahreb77hgM9khBcWCSfwq0Qal/bzU9AzBSUMEDErTdExBRHsBH2dDmBa1NvR38wVGn70SPEglI0VIvUFc2AI=", 38 | "verify": { 39 | "attribute-signed": "uid", 40 | "type": "ECDSA(secp256k1)" 41 | } 42 | }, 43 | "receipt": { 44 | "@context": "https://w3id.org/chainpoint/v2", 45 | "type": "ChainpointSHA256v2", 46 | "targetHash": "3e23e8160039594a33894f6564e1b1348bbd7a0088d42c4acb73eeaed59c009d", 47 | "merkleRoot": "d71f8983ad4ee170f8129f1ebcdd7440be7798d8e1c80420bf11f1eced610dba", 48 | "proof": [ 49 | { 50 | "left": "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb" 51 | }, 52 | { 53 | "right": "bffe0b34dba16bc6fac17c08bac55d676cded5a4ade41fe2c9924a5dde8f3e5b" 54 | }, 55 | { 56 | "right": "3f79bb7b435b05321651daefd374cdc681dc06faa65e374e38337b88ca046dea" 57 | } 58 | ], 59 | "anchors": [ 60 | { 61 | "type": "BTCOpReturn", 62 | "sourceId": "b84a92f28cc9dbdc4cd51834f6595cf97f018b925167c299097754780d7dea09" 63 | } 64 | ] 65 | } 66 | } -------------------------------------------------------------------------------- /examples/1.2/sample_signed_cert_multiple_signers-1.2.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": "https://w3id.org/blockcerts/v1", 3 | "type": "BlockchainCertificate", 4 | "document": { 5 | "type": "CertificateDocument", 6 | "assertion": { 7 | "type": "Assertion", 8 | "evidence": "", 9 | "id": "http://www.theissuer.edu/fb9e6259-f3ee-438a-b98f-a24f54187af8", 10 | "image:signature": [ 11 | { 12 | "jobTitle": "President", 13 | "image": "data:image/png;base64," 14 | }, 15 | { 16 | "jobTitle": "Vice-President", 17 | "image": "data:image/png;base64," 18 | } 19 | ], 20 | "issuedOn": "2016-05-26T12:00:00Z", 21 | "uid": "fb9e6259-f3ee-438a-b98f-a24f54187af8" 22 | }, 23 | "certificate": { 24 | "type": "Certificate", 25 | "description": "Certificate description", 26 | "image": "data:image/png;base64,", 27 | "issuer": { 28 | "type": "Issuer", 29 | "email": "issuer@theissuer.edu", 30 | "id": "https://www.theissuer.edu/issuer/the-issuer.json", 31 | "image": "data:image/png;base64,", 32 | "name": "Issuing Institution", 33 | "url": "http://www.theissuer.edu" 34 | }, 35 | "subtitle": "2016", 36 | "name": "Certificate name" 37 | }, 38 | "recipient": { 39 | "familyName": "RecipientLastName", 40 | "givenName": "RecipientFirstName", 41 | "hashed": false, 42 | "identity": "recipient@domain.com", 43 | "publicKey": "1GCrFRozNVWCqTreV7ZoXudiotknoJeXaz", 44 | "type": "email" 45 | }, 46 | "signature": "IAhahreb77hgM9khBcWCSfwq0Qal/bzU9AzBSUMEDErTdExBRHsBH2dDmBa1NvR38wVGn70SPEglI0VIvUFc2AI=", 47 | "verify": { 48 | "attribute-signed": "uid", 49 | "type": "ECDSA(secp256k1)" 50 | } 51 | }, 52 | "receipt": { 53 | "@context": "https://w3id.org/chainpoint/v2", 54 | "type": "ChainpointSHA256v2", 55 | "targetHash": "3e23e8160039594a33894f6564e1b1348bbd7a0088d42c4acb73eeaed59c009d", 56 | "merkleRoot": "d71f8983ad4ee170f8129f1ebcdd7440be7798d8e1c80420bf11f1eced610dba", 57 | "proof": [ 58 | { 59 | "left": "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb" 60 | }, 61 | { 62 | "right": "bffe0b34dba16bc6fac17c08bac55d676cded5a4ade41fe2c9924a5dde8f3e5b" 63 | }, 64 | { 65 | "right": "3f79bb7b435b05321651daefd374cdc681dc06faa65e374e38337b88ca046dea" 66 | } 67 | ], 68 | "anchors": [ 69 | { 70 | "type": "BTCOpReturn", 71 | "sourceId": "b84a92f28cc9dbdc4cd51834f6595cf97f018b925167c299097754780d7dea09" 72 | } 73 | ] 74 | } 75 | } -------------------------------------------------------------------------------- /examples/1.2/sample_unsigned_cert-1.2.json: -------------------------------------------------------------------------------- 1 | { 2 | "@context": "https://www.blockcerts.org/schema/1.2/context.json", 3 | "type": "BlockchainCertificate", 4 | "document": { 5 | "type": "CertificateDocument", 6 | "assertion": { 7 | "type": "Assertion", 8 | "evidence": "", 9 | "id": "http://www.theissuer.edu/fb9e6259-f3ee-438a-b98f-a24f54187af8", 10 | "image:signature": "data:image/png;base64,", 11 | "issuedOn": "2016-05-26T12:00:00Z", 12 | "uid": "fb9e6259-f3ee-438a-b98f-a24f54187af8" 13 | }, 14 | "certificate": { 15 | "type": "Certificate", 16 | "description": "Certificate description", 17 | "image": "data:image/png;base64,", 18 | "issuer": { 19 | "type": "Issuer", 20 | "email": "issuer@theissuer.edu", 21 | "id": "https://www.theissuer.edu/issuer/the-issuer.json", 22 | "image": "data:image/png;base64,", 23 | "name": "Issuing Institution", 24 | "url": "http://www.theissuer.edu" 25 | }, 26 | "subtitle": "2016", 27 | "name": "Certificate name" 28 | }, 29 | "recipient": { 30 | "familyName": "RecipientLastName", 31 | "givenName": "RecipientFirstName", 32 | "hashed": false, 33 | "identity": "recipient@domain.com", 34 | "publicKey": "1GCrFRozNVWCqTreV7ZoXudiotknoJeXaz", 35 | "type": "email" 36 | }, 37 | "verify": { 38 | "attribute-signed": "uid", 39 | "type": "ECDSA(secp256k1)" 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /release_package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | python setup.py register -r pypi 4 | python setup.py sdist upload -r pypi 5 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pyld>=0.8.1 2 | jsonschema>=2.6.0 3 | requests>=2.18.4 4 | tox>=2.7.0 5 | validators>=0.12.0 6 | -------------------------------------------------------------------------------- /run_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | tox -------------------------------------------------------------------------------- /scripts/generateMarkdown-experiment.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This has experimental improvements to the generate_markdown.js script. Still not complete, but better at handling 3 | * referenced schemas and types. 4 | */ 5 | var parse = require('json-schema-to-markdown'); 6 | var fs = require('fs'); 7 | 8 | function writeMarkdownToFile(filename, markdown){ 9 | fs.writeFile(filename, markdown, function(err) { 10 | if(err) { 11 | return console.log(err); 12 | } 13 | }); 14 | } 15 | 16 | 17 | var schemas = [ 18 | '../cert_schema/2.0/issuerSchema.json' 19 | ]; 20 | 21 | for (var i = 0; i < schemas.length; i++) { 22 | var schema = schemas[i]; 23 | 24 | // build 'out' file name 25 | var parts = schema.split('/'); 26 | var lastPart = parts[parts.length - 1]; 27 | var secondToLastPart = ''; 28 | if (parts.length > 2) { 29 | secondToLastPart = parts[parts.length - 2] + '_'; 30 | } 31 | var fileName = lastPart.substring(0, lastPart.length - 5); 32 | 33 | // convert 34 | var certschema = require(schema); 35 | var certmarkdown = parse(certschema); 36 | 37 | console.log('Writing markdown to ' + secondToLastPart + fileName); 38 | 39 | writeMarkdownToFile(secondToLastPart + fileName + '.md', certmarkdown) 40 | } 41 | -------------------------------------------------------------------------------- /scripts/generate_markdown.js: -------------------------------------------------------------------------------- 1 | var parse = require('json-schema-to-markdown'); 2 | var fs = require('fs'); 3 | 4 | function writeMarkdownToFile(filename, markdown){ 5 | fs.writeFile(filename, markdown, function(err) { 6 | if(err) { 7 | return console.log(err); 8 | } 9 | }); 10 | } 11 | 12 | /* 13 | var certschema = require('../cert_schema/schema/certificate/1.1/certificate-schema-v1-1.json'); 14 | var certmarkdown = parse(certschema); 15 | writeMarkdownToFile('docs/certificate-schema-v1-1.md', certmarkdown); 16 | */ 17 | 18 | var schemas = ['../cert_schema/1.2/assertion-1.2.json', 19 | '../cert_schema/1.2/blockchain-certificate-1.2.json', 20 | '../cert_schema/1.2/blockchain-receipt-1.2.json', 21 | '../cert_schema/1.2/certificate-1.2.json', 22 | '../cert_schema/1.2/certificate-document-1.2.json', 23 | '../cert_schema/1.2/issuer-1.2.json', 24 | '../cert_schema/1.2/issuer-id-1.2.json']; 25 | 26 | for (var i = 0; i < schemas.length; i++) { 27 | var schema = schemas[i]; 28 | 29 | // build 'out' file name 30 | var parts = schema.split('/'); 31 | var lastPart = parts[parts.length - 1]; 32 | var fileName = lastPart.substring(0, lastPart.length - 5); 33 | 34 | // convert 35 | var certschema = require(schema); 36 | var certmarkdown = parse(certschema); 37 | 38 | console.log('Writing markdown to ' + fileName); 39 | 40 | writeMarkdownToFile('docs/' + fileName + '.md', certmarkdown) 41 | } 42 | 43 | 44 | /* 45 | var issuerschema = require('../cert_schema/schema/issuer-keys/1.1/issuer-schema-v1-1.json') 46 | var issuermarkdown = parse(issuerschema) 47 | writeMarkdownToFile('../docs/issuer-schema-v1-1.md', issuermarkdown)*/ 48 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import os 2 | import uuid 3 | 4 | from pip.req import parse_requirements 5 | from setuptools import setup, find_packages 6 | 7 | here = os.path.abspath(os.path.dirname(__file__)) 8 | 9 | install_reqs = parse_requirements(os.path.join(here, 'requirements.txt'), session=uuid.uuid1()) 10 | reqs = [str(ir.req) for ir in install_reqs] 11 | 12 | with open(os.path.join(here, 'README.md')) as fp: 13 | long_description = fp.read() 14 | 15 | setup( 16 | name='cert-schema', 17 | version='2.1.4', 18 | description='Blockchain certificates JSON-LD context and JSON schemas', 19 | author='info@blockcerts.org', 20 | url='https://github.com/blockchain-certificates/cert-schema', 21 | license='MIT', 22 | author_email='info@blockcerts.org', 23 | long_description=long_description, 24 | packages=find_packages(), 25 | package_data={"cert_schema": ["1.1/*.json", "1.2/*.json", "2.0-alpha/*.json", "2.0/*.json"]}, 26 | install_requires=reqs 27 | ) 28 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/1EdTech/cert-schema/6fc8bbf29ae9ef0d1823768b10ae9bd1aebb2c9d/tests/__init__.py -------------------------------------------------------------------------------- /tests/test_jsonld_helpers.py: -------------------------------------------------------------------------------- 1 | import json 2 | import unittest 3 | 4 | from cert_schema import BlockcertValidationError 5 | from cert_schema import normalize_jsonld 6 | 7 | 8 | class TestJsonldHelpers(unittest.TestCase): 9 | def test_v2_unmapped_fields(self): 10 | with self.assertRaises(BlockcertValidationError): 11 | with open('../examples/2.0-alpha/tampered_unmapped_fields.json') as data_f: 12 | certificate = json.load(data_f) 13 | normalize_jsonld(certificate, detect_unmapped_fields=True) 14 | 15 | def test_v2_preloaded_loader(self): 16 | with open('../examples/2.0-alpha/sample_valid.json') as data_f: 17 | certificate = json.load(data_f) 18 | normalize_jsonld(certificate, detect_unmapped_fields=True) 19 | 20 | def test_v2_unmapped_fields_with_vocab(self): 21 | with open('../examples/2.0-alpha/tampered_unmapped_fields_vocab.json') as data_f: 22 | certificate = json.load(data_f) 23 | normalize_jsonld(certificate, detect_unmapped_fields=True) -------------------------------------------------------------------------------- /tests/test_schema_validator.py: -------------------------------------------------------------------------------- 1 | import json 2 | import unittest 3 | 4 | from cert_schema import BlockcertValidationError 5 | from cert_schema import schema_validator 6 | from cert_schema import validate_unsigned_v1_2 7 | from cert_schema import validate_v1_2 8 | from cert_schema import validate_v2 9 | from cert_schema.schema_validator import validate_v2_alpha 10 | 11 | 12 | class TestSchemaValidator(unittest.TestCase): 13 | def test_v1_unsigned(self): 14 | valid = schema_validator.validate('../examples/1.1/sample_unsigned_cert-1.1.json', 15 | '../cert_schema/1.1/certificate-schema-v1-1.json') 16 | self.assertTrue(valid) 17 | 18 | def test_v1_signed(self): 19 | valid = schema_validator.validate('../examples/1.1/sample_signed_cert-1.1.json', 20 | '../cert_schema/1.1/certificate-schema-v1-1.json') 21 | self.assertTrue(valid) 22 | 23 | def test_v1_2_signed(self): 24 | with open('../examples/1.2/sample_signed_cert-1.2.json') as data_f: 25 | certificate = json.load(data_f) 26 | valid = validate_v1_2(certificate) 27 | self.assertTrue(valid) 28 | 29 | def test_v1_2_invalid(self): 30 | with open('../examples/1.2/sample_invalid_cert-1.2.json') as data_f: 31 | certificate = json.load(data_f) 32 | try: 33 | valid = validate_v1_2(certificate) 34 | except BlockcertValidationError as bve: 35 | self.assertTrue(True, 'Got validation error, as expected') 36 | return 37 | self.fail('Did not get expected validation error') 38 | 39 | def test_v1_2_signed_multiple_signers(self): 40 | with open('../examples/1.2/sample_signed_cert_multiple_signers-1.2.json') as data_f: 41 | certificate = json.load(data_f) 42 | valid = validate_v1_2(certificate) 43 | self.assertTrue(valid) 44 | 45 | def test_v1_2_unsigned(self): 46 | with open('../examples/1.2/sample_unsigned_cert-1.2.json') as data_f: 47 | data = json.load(data_f) 48 | valid = validate_unsigned_v1_2(data['document']) 49 | self.assertTrue(valid) 50 | 51 | def test_v2_alpha(self): 52 | with open('../examples/2.0-alpha/sample_valid.json') as data_f: 53 | certificate = json.load(data_f) 54 | valid = validate_v2_alpha(certificate) 55 | self.assertTrue(valid) 56 | 57 | def test_v2(self): 58 | with open('../examples/2.0/bbba8553-8ec1-445f-82c9-a57251dd731c.json') as data_f: 59 | certificate = json.load(data_f) 60 | valid = validate_v2(certificate) 61 | self.assertTrue(valid) 62 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | # Tox (http://tox.testrun.org/) is a tool for running tests 2 | # in multiple virtualenvs. This configuration file will run the 3 | # test suite on all supported python versions. To use it, "pip install tox" 4 | # and then run "tox" from this directory. 5 | 6 | [tox] 7 | envlist = py27,py34,py36 8 | 9 | [testenv] 10 | changedir=tests 11 | deps=pytest 12 | 13 | commands= 14 | py.test --basetemp={envtmpdir} {posargs} # substitute with tox' positional arguments 15 | --------------------------------------------------------------------------------