Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3/4] In-memory issuing: unsigned certificate creation. #41

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 9 additions & 13 deletions cert_tools/create_v2_certificate_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,53 +8,49 @@
import uuid

import configargparse
from cert_core.cert_model.model import scope_name
from cert_schema import OPEN_BADGES_V2_CANONICAL_CONTEXT, BLOCKCERTS_V2_CANONICAL_CONTEXT

from cert_tools import helpers
from cert_tools import jsonpath_helpers

from cert_core.cert_model.model import scope_name
from cert_schema import OPEN_BADGES_V2_CANONICAL_CONTEXT, BLOCKCERTS_V2_CANONICAL_CONTEXT
from cert_tools.helpers import get_b64encoded_image

OPEN_BADGES_V2_CONTEXT = OPEN_BADGES_V2_CANONICAL_CONTEXT
BLOCKCERTS_V2_CONTEXT = BLOCKCERTS_V2_CANONICAL_CONTEXT


def create_badge_section(config):
cert_image_path = os.path.join(config.abs_data_dir, config.cert_image_file)
issuer_image_path = os.path.join(config.abs_data_dir, config.issuer_logo_file)
badge = {
'type': 'BadgeClass',
'id': helpers.URN_UUID_PREFIX + config.badge_id,
'name': config.certificate_title,
'description': config.certificate_description,
'image': helpers.encode_image(cert_image_path),
'image': get_b64encoded_image(config, 'cert_image_file'),
'issuer': {
'id': config.issuer_id,
'type': 'Profile',
'name': config.issuer_name,
'url': config.issuer_url,
'email': config.issuer_email,
'image': helpers.encode_image(issuer_image_path),
'revocationList': config.revocation_list
'image': get_b64encoded_image(config, 'issuer_logo_file'),
'revocationList': config.revocation_list_uri
}
}

badge['criteria'] = {}
badge['criteria']['narrative'] = config.criteria_narrative

if config.issuer_signature_lines:
signature_lines = []
signature_lines = []
for signature_line in config.issuer_signature_lines:
signature_image_path = os.path.join(config.abs_data_dir, signature_line['signature_image'])
signature_lines.append(
{
'type': [
'SignatureLine',
'Extension'
],
'jobTitle': signature_line['job_title'],
'image': helpers.encode_image(signature_image_path),
'image': get_b64encoded_image(config, 'issuer_signature_file'),
'name': signature_line['name']
}
)
Expand Down Expand Up @@ -107,7 +103,6 @@ def create_assertion_section(config):


def create_certificate_template(config):

if not config.badge_id:
badge_uuid = str(uuid.uuid4())
print('Generated badge id {0}'.format(badge_uuid))
Expand Down Expand Up @@ -157,6 +152,7 @@ def get_config():

p.add('-c', '--my-config', required=False, is_config_file=True, help='config file path')

p.add_argument('--no_files', action='store_true', help='avoid using files as intermediate or final results')
p.add_argument('--data_dir', type=str, help='where data files are located')
p.add_argument('--issuer_logo_file', type=str, help='issuer logo image file, png format')
p.add_argument('--cert_image_file', type=str, help='issuer logo image file, png format')
Expand All @@ -173,7 +169,7 @@ def get_config():
p.add_argument('--template_file_name', type=str, help='the template file name')
p.add_argument('--hash_emails', action='store_true',
help='whether to hash emails in the certificate')
p.add_argument('--revocation_list', type=str, help='issuer revocation list')
p.add_argument('--revocation_list_uri', type=str, help='issuer revocation list')
p.add_argument('--issuer_public_key', type=str, help='issuer public key')
p.add_argument('--badge_id', required=True, type=str, help='badge id')
p.add_argument('--issuer_signature_lines', action=helpers.make_action('issuer_signature_lines'),
Expand Down
53 changes: 31 additions & 22 deletions cert_tools/create_v2_issuer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@

Currently, just not check for inputs' validity (e.g. valid address, URLs, etc.)
'''
import json
import os
import sys
from cert_schema import *

import configargparse
import json
from cert_schema import *

from cert_tools import helpers

Expand All @@ -18,46 +19,54 @@
BLOCKCERTS_V2_CONTEXT_JSON = BLOCKCERTS_V2_CANONICAL_CONTEXT


def generate_issuer_file(config):
def generate_issuer_file(config, issuer):
issuer_json = generate_issuer(config)

output_handle = open(config.output_file, 'w') if (
hasattr(config, 'output_file') and config.output_file) else sys.stdout

output_handle.write(json.dumps(issuer_json, indent=2))

if output_handle is not sys.stdout:
output_handle.close()

if config.public_key_created:

def generate_issuer(config):
if hasattr(config, 'public_key_created') and config.public_key_created:
issued_on = config.public_key_created
else:
issued_on = helpers.create_iso8601_tz()
output_handle = open(config.output_file, 'w') if config.output_file else sys.stdout

context = [OPEN_BADGES_V2_CONTEXT_JSON, BLOCKCERTS_V2_CONTEXT_JSON]

issuer_json = {
issuer = {
'@context': context,
'id': config.issuer_id,
'url': config.issuer_url,
'name': config.issuer_name,
'email': config.issuer_email,
'image': helpers.encode_image(os.path.join(config.abs_data_dir, config.issuer_logo_file)),
'image': helpers.get_b64encoded_image(config, 'issuer_logo_file'),
'publicKey': [{'id': config.issuer_public_key, "created": issued_on}],
'revocationList': config.revocation_list_uri,
'type': ISSUER_TYPE
}

if config.intro_url:
issuer_json['introductionUrl'] = config.intro_url

output_handle.write(json.dumps(issuer_json, indent=2))

if output_handle is not sys.stdout:
output_handle.close()
issuer['introductionUrl'] = config.intro_url
return issuer


def get_config():
cwd = os.getcwd()
p = configargparse.getArgumentParser(default_config_files=[os.path.join(cwd, 'conf.ini')])
p.add('-c', '--my-config', required=True, is_config_file=True, help='config file path')
p.add_argument('--no_files', action='store_true', help='avoid using files as intermediate or final results')
p.add_argument('--data_dir', type=str, help='where data files are located')
p.add_argument('-k', '--issuer_public_key', type=str, required=True, help='The key(s) an issuer uses to sign Assertions. See https://openbadgespec.org/#Profile for more details')
p.add_argument('-k', '--public_key_created', type=str, help='ISO8601-formatted date the issuer public key should be considered active')
p.add_argument('-r', '--revocation_list_uri', type=str, required=True, help='URI of the Revocation List used for marking revocation. See https://openbadgespec.org/#Profile for more details')
p.add_argument('-d', '--issuer_id', type=str, required=True, help='the issuer\'s publicly accessible identification file; i.e. URL of the file generated by this tool')
p.add_argument('-k', '--issuer_public_key', type=str, required=True,
help='The key(s) an issuer uses to sign Assertions. See https://openbadgespec.org/#Profile for more details')
p.add_argument('-k', '--public_key_created', type=str,
help='ISO8601-formatted date the issuer public key should be considered active')
p.add_argument('-r', '--revocation_list_uri', type=str, required=True,
help='URI of the Revocation List used for marking revocation. See https://openbadgespec.org/#Profile for more details')
p.add_argument('-d', '--issuer_id', type=str, required=True,
help='the issuer\'s publicly accessible identification file; i.e. URL of the file generated by this tool')
p.add_argument('-u', '--issuer_url', type=str, help='the issuer\'s main URL address')
p.add_argument('-n', '--issuer_name', type=str, help='the issuer\'s name')
p.add_argument('-e', '--issuer_email', type=str, help='the issuer\'s email')
Expand All @@ -72,9 +81,9 @@ def get_config():

def main():
conf = get_config()
generate_issuer_file(conf)
issuer = generate_issuer(conf)
generate_issuer_file(conf, issuer)


if __name__ == "__main__":
main()

9 changes: 7 additions & 2 deletions cert_tools/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from datetime import datetime, timezone

import configargparse
import pytz

if sys.version > '3':
from urllib.parse import urljoin
Expand Down Expand Up @@ -58,4 +57,10 @@ def encode(num, alphabet=BASE62):

def create_iso8601_tz():
ret = datetime.now(timezone.utc)
return ret.isoformat()
return ret.isoformat()


def get_b64encoded_image(config, image_field):
if config.no_files:
return config[image_field]
return encode_image(os.path.join(config.abs_data_dir, config[image_field]))
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ configargparse>=0.13.0
jsonpath-rw>=1.4.0
pycoin>=0.80
tox>=3.0.0
pytest==5.1.1
attrdict==2.0.1
84 changes: 84 additions & 0 deletions tests/conftest.py

Large diffs are not rendered by default.

143 changes: 137 additions & 6 deletions tests/test_cert_tools.py

Large diffs are not rendered by default.