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

feat: digital credentials #2287

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
58e63e2
feat: devcontainer configuraton for vscode
amanji Sep 7, 2023
107604e
feat: hard code digital business card schema
amanji Sep 7, 2023
3793db1
feat: hard code digital business card schema
amanji Sep 7, 2023
d0c51ce
feat: issue credentials through Traction tenant
amanji Sep 11, 2023
7b88982
refactor: app initialization workflow
amanji Sep 12, 2023
ad0fa01
feat: use out-of-band invitation for connecting
amanji Sep 20, 2023
2e75d5f
feat: use v2.0 for issuing credential
amanji Sep 21, 2023
79a2631
feat: web socket implmentation with flask-socketio
amanji Oct 11, 2023
fc8edc4
feat: db migration script to enable revocation
amanji Oct 16, 2023
4fe8406
feat: revocation endpoint
amanji Oct 18, 2023
aec27f2
feat: replace endpoints
amanji Oct 19, 2023
99e54fe
chore: fix linting errors
amanji Oct 19, 2023
88e3ccc
chore: update requirements
amanji Oct 19, 2023
fd96a6e
chore: update tests
amanji Oct 25, 2023
e397e04
feat: traction token exchanger
amanji Oct 26, 2023
1f2fe2b
chore: update workflow variables
amanji Oct 26, 2023
4090b35
chore: update workflow variables
amanji Oct 26, 2023
7f1f546
refactor: ws cors setting is a config option
amanji Oct 26, 2023
a259818
chore: fix linting errors
amanji Oct 26, 2023
080825f
refactor: clean up init in digital credential service
amanji Oct 27, 2023
87d0854
feat: endpoints to reset credential offers
amanji Oct 28, 2023
4042676
Merge remote-tracking branch 'upstream/feature-digital-credentials' i…
amanji Oct 30, 2023
26a01e7
feat: credential id lookup table
amanji Oct 30, 2023
32a7d7a
feat: add business roles
amanji Oct 30, 2023
c55cebc
chore: fix tests and linting
amanji Oct 30, 2023
8ad8cb9
chore: fix tests
amanji Oct 31, 2023
2fc5cb3
Merge remote-tracking branch 'upstream/feature-digital-credentials' i…
amanji Oct 31, 2023
d368673
refactor: remove records from Traction on deletion
amanji Nov 1, 2023
0b3b60b
Revert "feat: web socket implmentation with flask-socketio"
amanji Nov 1, 2023
9763a17
fix: port so it doesnt overlap with airplay server on OSX
amanji Nov 1, 2023
633e3d9
Revert "fix: port so it doesnt overlap with airplay server on OSX"
amanji Nov 1, 2023
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
5 changes: 1 addition & 4 deletions legal-api/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,7 @@ tag: push ## tag image
# COMMANDS - Local #
#################################################################################
run: ## Run the project in local
. venv/bin/activate && python -m flask run -p 5050

run-websockets: ## Run the project in local with websockets
. venv/bin/activate && python -m gunicorn --threads 100 --bind :5050 wsgi
. venv/bin/activate && python -m flask run -p 5000

#################################################################################
# Self Documenting Commands #
Expand Down
14 changes: 7 additions & 7 deletions legal-api/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,15 @@ Flask-Moment==0.11.0
Flask-Pydantic==0.8.0
Flask-SQLAlchemy==2.5.1
Flask-Script==2.0.6
Flask-SocketIO==5.3.6
Flask==1.1.2
Jinja2==2.11.3
Mako==1.1.4
MarkupSafe==1.1.1
PyPDF2==1.26.0
SQLAlchemy-Continuum==1.3.13
SQLAlchemy-Utils==0.37.8
SQLAlchemy==1.4.44
Werkzeug==1.0.1
nest_asyncio
alembic==1.7.5
aniso8601==9.0.1
asyncio-nats-client==0.11.4
Expand All @@ -32,15 +31,11 @@ ecdsa==0.14.1
expiringdict==1.1.4
flask-jwt-oidc==0.3.0
flask-restx==0.3.0
git+https://github.com/bcgov/business-schemas.git@2.18.13#egg=registry_schemas
gunicorn==20.1.0
html-sanitizer==1.9.3
idna==2.10
itsdangerous==1.1.0
jsonschema==4.19.0
launchdarkly-server-sdk==7.1.0
minio==7.0.2
nest_asyncio
protobuf==3.15.8
psycopg2-binary==2.8.6
pyRFC3339==1.1
Expand All @@ -54,11 +49,16 @@ python-dotenv==0.17.1
python-editor==1.0.4
python-jose==3.2.0
pytz==2021.1
reportlab==3.6.12
requests==2.25.1
rsa==4.7.2
semver==2.13.0
sentry-sdk==1.20.0
six==1.15.0
strict-rfc3339==0.7
urllib3==1.26.11
minio==7.0.2
PyPDF2==1.26.0
reportlab==3.6.12
html-sanitizer==1.9.3
git+https://github.com/bcgov/business-schemas.git@2.18.13#egg=registry_schemas

6 changes: 0 additions & 6 deletions legal-api/src/legal_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
from registry_schemas.flask import SchemaServices # noqa: I001

from legal_api import config, models
from legal_api.extensions import socketio
from legal_api.models import db
from legal_api.resources import endpoints
from legal_api.schemas import rsbc_schemas
Expand Down Expand Up @@ -68,11 +67,6 @@ def create_app(run_mode=os.getenv('FLASK_ENV', 'production')):

register_shellcontext(app)

ws_allowed_origins = app.config.get('WS_ALLOWED_ORIGINS', [])
if isinstance(ws_allowed_origins, str) and ws_allowed_origins != '*':
ws_allowed_origins = ws_allowed_origins.split(',')
socketio.init_app(app, cors_allowed_origins=ws_allowed_origins)

return app


Expand Down
25 changes: 0 additions & 25 deletions legal-api/src/legal_api/extensions.py

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
from flask import Blueprint, _request_ctx_stack, current_app, jsonify, request
from flask_cors import cross_origin

from legal_api.extensions import socketio
from legal_api.models import (
Business,
CorpType,
Expand Down Expand Up @@ -104,6 +103,11 @@ def delete_connection(identifier, connection_id):
if not connection:
return jsonify({'message': f'{identifier} connection not found.'}), HTTPStatus.NOT_FOUND

try:
digital_credentials.remove_connection_record(connection_id=connection.connection_id)
except Exception:
return jsonify({'message': 'Failed to remove connection record.'}), HTTPStatus.INTERNAL_SERVER_ERROR

connection.delete()
return jsonify({'message': 'Connection has been deleted.'}), HTTPStatus.OK

Expand All @@ -121,6 +125,11 @@ def delete_active_connection(identifier):
if not connection:
return jsonify({'message': f'{identifier} active connection not found.'}), HTTPStatus.NOT_FOUND

try:
digital_credentials.remove_connection_record(connection_id=connection.connection_id)
except Exception:
return jsonify({'message': 'Failed to remove connection record.'}), HTTPStatus.INTERNAL_SERVER_ERROR

connection.delete()
return jsonify({'message': 'Connection has been deleted.'}), HTTPStatus.OK

Expand Down Expand Up @@ -243,6 +252,11 @@ def delete_credential(identifier, credential_id):
if not issued_credential:
return jsonify({'message': f'{identifier} issued credential not found.'}), HTTPStatus.NOT_FOUND

try:
digital_credentials.remove_credential_exchange_record(issued_credential.credential_exchange_id)
except Exception:
return jsonify({'message': 'Failed to remove credential exchange record.'}), HTTPStatus.INTERNAL_SERVER_ERROR

issued_credential.delete()
return jsonify({'message': 'Credential has been deleted.'}), HTTPStatus.OK

Expand All @@ -265,7 +279,6 @@ def webhook_notification(topic_name: str):
connection.connection_state = json_input['state']
connection.is_active = True
connection.save()
socketio.emit('connections', connection.json)
elif topic_name == 'issuer_cred_rev':
issued_credential = DCIssuedCredential.find_by_credential_exchange_id(json_input['cred_ex_id'])
if issued_credential and json_input['state'] == 'issued':
Expand All @@ -278,7 +291,6 @@ def webhook_notification(topic_name: str):
issued_credential.date_of_issue = datetime.utcnow()
issued_credential.is_issued = True
issued_credential.save()
socketio.emit('issue_credential_v2_0', issued_credential.json)
except Exception as err:
current_app.logger.error(err)
raise err
Expand Down
24 changes: 24 additions & 0 deletions legal-api/src/legal_api/services/digital_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,30 @@ def revoke_credential(self, connection_id, cred_rev_id: str, rev_reg_id: str) ->
self.app.logger.error(err)
return None

@requires_traction_auth
def remove_connection_record(self, connection_id: str) -> Optional[dict]:
"""Delete a connection."""
try:
response = requests.delete(self.api_url + '/connections/' + connection_id,
headers=self._get_headers())
response.raise_for_status()
return response.json()
except Exception as err:
self.app.logger.error(err)
return None

@requires_traction_auth
def remove_credential_exchange_record(self, cred_ex_id: str) -> Optional[dict]:
"""Delete a credential exchange."""
try:
response = requests.delete(self.api_url + '/issue-credential-2.0/records/' + cred_ex_id,
headers=self._get_headers())
response.raise_for_status()
return response.json()
except Exception as err:
self.app.logger.error(err)
return None

def _get_headers(self) -> dict:
return {
'Content-Type': 'application/json',
Expand Down
3 changes: 1 addition & 2 deletions legal-api/wsgi.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@
import os

from legal_api import create_app
from legal_api.extensions import socketio

# Openshift s2i expects a lower case name of application
application = create_app() # pylint: disable=invalid-name

if __name__ == "__main__":
server_port = os.environ.get('PORT', '8080')
socketio.run(application, debug=False, port=server_port, host='0.0.0.0')
application.run(debug=False, port=server_port, host='0.0.0.0')
Loading