Skip to content

Commit

Permalink
Initial impl. Not submitting correct vLEI data to vLEI verification s…
Browse files Browse the repository at this point in the history
…ervice

Signed-off-by: 2byrds <[email protected]>
  • Loading branch information
2byrds authored and m00sey committed Jul 15, 2023
1 parent 63abeca commit 9a4e74f
Show file tree
Hide file tree
Showing 20 changed files with 427 additions and 0 deletions.
13 changes: 13 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# base image
FROM python:3.11-alpine

# set working directory
WORKDIR /usr/src/app/regps

# add app
COPY ./src /usr/src/app/regps/src
COPY ./setup.py /usr/src/app/regps/setup.py
COPY ./requirements.txt /usr/src/app/regps/requirements.txt

# install requirements
RUN pip install --no-cache-dir -r requirements.txt
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# regulation-portal-service
A service to manage regulator portal requests/responses that requires authentication, document submission, validation, and more

## Desgin
### Web app support
The web app (UI front-end) will be using Signify/KERIA for selecting identifiers and credentials:

### This service
The regulation service will provide the ability to:
* Login using an AID, SAID, and vLEI
* Upload signed files
* Check the status of an upload

## Development
You need to run a local vLEI service, see https://github.com/GLEIF-IT/reg-poc-verifier:
```verifier server start --config-dir scripts --config-file verifier-config.json```

To start this web service:
```docker-compose up -d --build```
To tear this web service:
```docker-compose down```

You should see:
```[+] Running 4/4
✔ Network reg-poc-server_default Created 0.1s
✔ Container reg-poc-server-redis-1 Started 0.6s
✔ Container web Started 0.8s
✔ Container reg-poc-server-celery-1 Started
```

You can run a test query using Swagger by going to:
```
http://127.0.0.1:8000/api/doc#
```

33 changes: 33 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
version: '3.8'

services:

web:
build: ./
image: web
container_name: web
ports:
- 8000:8000
volumes:
- ./:/usr/src/app/regps
command: sh -c "cd src/regps/ && gunicorn -b 0.0.0.0:8000 app:app --reload"
environment:
- CELERY_BROKER=redis://redis:6379/0
- CELERY_BACKEND=redis://redis:6379/0
depends_on:
- redis

celery:
image: web
volumes:
- ./:/usr/src/app/regps
command: sh -c "cd src/regps/ && celery -A app.tasks worker --loglevel=debug"
environment:
- CELERY_BROKER=redis://redis:6379/0
- CELERY_BACKEND=redis://redis:6379/0
depends_on:
- web
- redis

redis:
image: redis:7-alpine
10 changes: 10 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# requirements.txt
# Best practices for setup.py vs requirements.txt
# https://caremad.io/posts/2013/07/setup-vs-requirement/
# https://pip.pypa.io/en/stable/reference/pip_install/#install-index-url

# enables pip install -r requirements.txt to work with setup.py dependencies
# pull the dependencies from setup.py for keri from pip index
--index-url https://pypi.org/simple/ # pypi base pip index or local pip index

--editable . # install as editable
99 changes: 99 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
$ python setup.py register sdist upload
First Time register project on pypi
https://pypi.org/manage/projects/
Update sphinx /docs
$ cd /docs
$ sphinx-build -b html source build/html
or
$ sphinx-apidoc -f -o source/ ../src/
$ make html
Best practices for setup.py and requirements.txt
https://caremad.io/posts/2013/07/setup-vs-requirement/
"""


from glob import glob
from os.path import basename
from os.path import splitext

from setuptools import find_packages
from setuptools import setup

setup(
name='reg-portal-service',
version='0.0.1', # also change in src/regps/__init__.py
license='Apache Software License 2.0',
description='RegPS: Regulation Portal Service.',
long_description="RegPS: A Regulation Portal Service to orchestate web app, vLEI validation, etc.",
author='Lance Byrd',
author_email='[email protected]',
url='https://github.com/roots-id/regulation-portal-service',
packages=find_packages('src'),
package_dir={'': 'src'},
py_modules=[splitext(basename(path))[0] for path in glob('src/*.py')],
include_package_data=True,
zip_safe=False,
classifiers=[
# complete classifier list: http://pypi.python.org/pypi?%3Aaction=list_classifiers
'Development Status :: 3 - Alpha',
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License',
'Operating System :: Unix',
'Operating System :: POSIX',
'Operating System :: Microsoft :: Windows',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: Implementation :: CPython',
# uncomment if you test on these interpreters:
# 'Programming Language :: Python :: Implementation :: PyPy',
# 'Programming Language :: Python :: Implementation :: IronPython',
# 'Programming Language :: Python :: Implementation :: Jython',
# 'Programming Language :: Python :: Implementation :: Stackless',
'Topic :: Utilities',
],
project_urls={
'Issue Tracker': 'https://github.com/roots-id/regulation-portal-service/issues',
},
keywords=[
"secure attribution",
"authentic data",
"regulatory compliance",
"vLEI",
# eg: 'keyword1', 'keyword2', 'keyword3',
],
python_requires='>=3.10.4',
install_requires=[
'apispec>=6.3.0',
'asyncio>=3.4.3',
'celery>=5.3.0',
'dataclasses_json>=0.5.7',
'falcon>=3.1.0',
'http_sfv>=0.9.8',
'redis>=4.5.5',
'requests>=2.31.0',
'swagger-ui-py>=22.7.13',
'gunicorn>=20.1.0',
],
extras_require={
# eg:
# 'rst': ['docutils>=0.11'],
# ':python_version=="2.6"': ['argparse'],
},
tests_require=[
'coverage>=5.5',
'pytest>=6.2.4',
],
setup_requires=[
],
entry_points={
'console_scripts': [
'regps = regps.app.cli.regps:main',
]
},
)
5 changes: 5 additions & 0 deletions src/regps/app/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from app.service import falcon_app, swagger_ui

print("Starting RegPS...")
app = falcon_app()
api_doc=swagger_ui(app)
Binary file added src/regps/app/__pycache__/__init__.cpython-311.pyc
Binary file not shown.
Binary file added src/regps/app/__pycache__/service.cpython-311.pyc
Binary file not shown.
Binary file added src/regps/app/__pycache__/tasks.cpython-311.pyc
Binary file not shown.
Empty file added src/regps/app/cli/__init__.py
Empty file.
Binary file not shown.
Empty file.
Binary file not shown.
Binary file not shown.
23 changes: 23 additions & 0 deletions src/regps/app/cli/commands/start.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# -*- encoding: utf-8 -*-
"""
Regulation portal service
regps.cli.regps.commands module
regulation portal servicecommand line interface
"""
import argparse

# from regps.app import service

d = "Runs regulation portal service\n"
d += "\tExample:\nregps\n"
parser = argparse.ArgumentParser(description=d)
parser.set_defaults(handler=lambda args: launch(args))
parser.add_argument('-V', '--version',
action='version',
version="0.0.1",
help="Prints out version of script runner.")
parser.add_argument('-p', '--port',
action='store',
default=4902,
help="Local port number the HTTP server listens on. Default is 4902.")
36 changes: 36 additions & 0 deletions src/regps/app/cli/regps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# -*- encoding: utf-8 -*-
"""
Regulation portal service
regps.app.cli.commands module
"""
import logging
import multicommand
import regps.app.service as service
import commands

def main():
parser = multicommand.create_parser(commands)
args = parser.parse_args()

if not hasattr(args, 'handler'):
parser.print_help()
return

try:
logging.info("******* Starting regulation portal service for %s listening: http/%s "
".******", args.http)

service.main(http=int(args.http))

logging.info("******* Ended reg portal service %s listening: http/%s"
".******", args.http)


except Exception as ex:
print(f"ERR: {ex}")
return -1


if __name__ == "__main__":
main()
1 change: 1 addition & 0 deletions src/regps/app/data/credential.cesr

Large diffs are not rendered by default.

120 changes: 120 additions & 0 deletions src/regps/app/service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# import asyncio
# import falcon.asgi
import falcon
from falcon import media
from falcon.http_status import HTTPStatus
import json
import os
from swagger_ui import api_doc
from app.tasks import verify
# import uvicorn

class LoginTask(object):

def on_post(self, req, resp):
print("LoginTask.on_post")
try:
raw_json = req.stream.read()
result = json.loads(raw_json)
print(f"LoginTask.on_post: result is {result}")
result = verify(result['aid'], result['said'], result['vlei'])
resp.status = result.status_code
resp.text = result.text
resp.content_type = result.content
except Exception as e:
print(f"LoginTask.on_post: Exception: {e}")
resp.status = falcon.HTTP_500


class HandleCORS(object):
def process_request(self, req, resp):
resp.set_header('Access-Control-Allow-Origin', '*')
resp.set_header('Access-Control-Allow-Methods', '*')
resp.set_header('Access-Control-Allow-Headers', '*')
resp.set_header('Access-Control-Max-Age', 1728000) # 20 days
if req.method == 'OPTIONS':
raise HTTPStatus(falcon.HTTP_200, body='\n')

class PingResource:
def on_get(self, req, resp):
"""Handles GET requests"""
resp.status = falcon.HTTP_200
resp.content_type = falcon.MEDIA_TEXT
resp.text = (
'Pong'
)

def getRequiredParam(body, name):
param = body.get(name)
if param is None:
raise falcon.HTTPBadRequest(description=f"required field '{name}' missing from request")

return param

def swagger_ui(app):
cesr = None
with open('app/data/credential.cesr', 'r') as file:
file_contents = file.read()
print("Loaded cesr cred data {}".format(file_contents))
config = {"openapi":"3.0.1",
"info":{"title":"Regulator portal service api","description":"Regulator web portal service api","version":"1.0.0"},
"servers":[{"url":"http://127.0.0.1:8000","description":"local server"}],
"tags":[{"name":"default","description":"default tag"}],
"paths":{"/ping":{"get":{"tags":["default"],"summary":"output pong.","responses":{"200":{"description":"OK","content":{"application/text":{"schema":{"type":"object","example":"Pong"}}}}}}},
"/login":{"post":{"tags":["default"],
"summary":"Given an AID and vLEI, returns information about the login",
"requestBody":{"required":"true","content":{"application/json":{"schema":{"type":"object","properties":{
"aid":{"type":"string","example":"EBcIURLpxmVwahksgrsGW6_dUw0zBhyEHYFk17eWrZfk"},
"said":{"type":"string","example":"EPmiOgVewnJB8Oev8v4roUqIFNn5SBgiV-ukHiLW81ot"},
"vlei":{"type":"string","example":f"{file_contents}"}
}}}}},
"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","example":{"status": "200 OK", "message": "AID and vLEI valid login"}}}}}}
}}
},
"components":{}}

doc = api_doc(app, config=config, url_prefix='/api/doc', title='API doc', editor=True)
return doc

def falcon_app():
app = falcon.App(middleware=falcon.CORSMiddleware(
allow_origins='*', allow_credentials='*',
expose_headers=['content-type', 'signature', 'signature-input'])
)
# if os.getenv("KERI_AGENT_CORS", "false").lower() in ("true", "1"):
app.add_middleware(middleware=HandleCORS())
print("CORS enabled")
# app.add_middleware(authing.SignatureValidationComponent(agency=agency, authn=authn, allowed=["/agent"]))
app.req_options.media_handlers.update(media.Handlers())
app.resp_options.media_handlers.update(media.Handlers())

# app = falcon.asgi.App()
ping = PingResource()
app.add_route('/ping', ping)
app.add_route('/login', LoginTask())

return app

# async def appl(scope, receive, send):
# assert scope['type'] == 'http'

# await send({
# 'type': 'http.response.start',
# 'status': 200,
# 'headers': [
# [b'content-type', b'text/plain'],
# ],
# })
# await send({
# 'type': 'http.response.body',
# 'body': b'Hello, world!',
# })

def main(first, second):
print("Starting RegPS...")
app = falcon_app()
api_doc=swagger_ui(app)
return app

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

0 comments on commit 9a4e74f

Please sign in to comment.