From 47fd0178a546f73324fcec0aa0ac00997efdd940 Mon Sep 17 00:00:00 2001 From: Lucas O'Neil Date: Thu, 29 Aug 2024 14:18:24 -0700 Subject: [PATCH] Dont use endorser service (#1344) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed unused endorser code and references Signed-off-by: Lucas ONeil Signed-off-by: Emiliano Suñé Co-authored-by: Emiliano Suñé --- .codeclimate.yml | 1 - .github/dependabot.yml | 21 --- README.md | 1 - scripts/.env-example | 2 - scripts/docker-compose.yml | 88 +--------- services/endorser/.dockerignore | 7 - services/endorser/.gitignore | 8 - services/endorser/Dockerfile | 11 -- services/endorser/README.md | 18 -- services/endorser/alembic.ini | 36 ---- services/endorser/api/acapy_utils.py | 157 ------------------ services/endorser/api/core/config.py | 108 ------------ services/endorser/api/endorser_main.py | 58 ------- .../endpoints/dependencies/jwt_security.py | 22 --- .../endorser/api/endpoints/routes/endorser.py | 14 -- .../endorser/api/endpoints/routes/webhooks.py | 101 ----------- services/endorser/api/logging.conf | 33 ---- services/endorser/api/main.py | 49 ------ services/endorser/docker-entrypoint.sh | 7 - services/endorser/requirements.txt | 32 ---- services/endorser/tests/__init__.py | 0 services/endorser/tests/test_main.py | 2 - services/endorser/tox.ini | 29 ---- 23 files changed, 5 insertions(+), 800 deletions(-) delete mode 100644 services/endorser/.dockerignore delete mode 100644 services/endorser/.gitignore delete mode 100644 services/endorser/Dockerfile delete mode 100644 services/endorser/README.md delete mode 100644 services/endorser/alembic.ini delete mode 100644 services/endorser/api/acapy_utils.py delete mode 100644 services/endorser/api/core/config.py delete mode 100644 services/endorser/api/endorser_main.py delete mode 100644 services/endorser/api/endpoints/dependencies/jwt_security.py delete mode 100644 services/endorser/api/endpoints/routes/endorser.py delete mode 100644 services/endorser/api/endpoints/routes/webhooks.py delete mode 100644 services/endorser/api/logging.conf delete mode 100644 services/endorser/api/main.py delete mode 100755 services/endorser/docker-entrypoint.sh delete mode 100644 services/endorser/requirements.txt delete mode 100644 services/endorser/tests/__init__.py delete mode 100644 services/endorser/tests/test_main.py delete mode 100644 services/endorser/tox.ini diff --git a/.codeclimate.yml b/.codeclimate.yml index 573fa60e5..cdb2db825 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -70,7 +70,6 @@ exclude_patterns: - ".vscode/" - "charts/" - "scripts/" - - "services/endorser/" - "services/tenant-ui/frontend/src/overlayLibrary" - "services/tenant-ui/frontend/src/types/acapyApi" - "services/traction/acapy_client/" diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6f98e87d8..11700ee33 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -13,18 +13,6 @@ updates: all-actions: patterns: [ "*" ] - # Maintain dependencies for Python Packages - - package-ecosystem: "pip" - directory: "/services/endorser" - schedule: - interval: "weekly" - day: "monday" - time: "04:00" - timezone: "Canada/Pacific" - ignore: - - dependency-name: "*" - update-types: ["version-update:semver-major"] - # Maintain dependencies for Python Packages - package-ecosystem: "pip" directory: "/plugins" @@ -126,15 +114,6 @@ updates: day: "monday" time: "04:00" timezone: "Canada/Pacific" - - # Maintain dependencies for docker - - package-ecosystem: "docker" - directory: "/services/endorser" - schedule: - interval: "weekly" - day: "monday" - time: "04:00" - timezone: "Canada/Pacific" # Maintain dependencies for docker - package-ecosystem: "docker" diff --git a/README.md b/README.md index 7ed09873f..ad49bc57f 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,6 @@ Traction makes it easier to integrate digital trust technology into existing lin - [ACA-Py + plugins](./plugins/README.md) - [Tenant UI](./services/tenant-ui/README.md) -- [Endorser Services](./services/endorser/README.md) ## Start contributing to Traction diff --git a/scripts/.env-example b/scripts/.env-example index f5cdb91ac..b0a114646 100644 --- a/scripts/.env-example +++ b/scripts/.env-example @@ -153,9 +153,7 @@ ENDORSER_1_ACAPY_WALLET_DATABASE=endorser-wallet-1 ENDORSER_ACAPY_WALLET_ENCRYPTION_KEY=key ENDORSER_POSTGRESQL_HOST=endorser-db -ENDORSER_1_POSTGRESQL_HOST=endorser-db-1 ENDORSER_POSTGRESQL_PORT=5433 -ENDORSER_1_POSTGRESQL_PORT=5434 ENDORSER_POSTGRESQL_USER=postgres ENDORSER_POSTGRESQL_PASSWORD=postgresPass diff --git a/scripts/docker-compose.yml b/scripts/docker-compose.yml index 4061b8e54..0c1630ca1 100755 --- a/scripts/docker-compose.yml +++ b/scripts/docker-compose.yml @@ -162,36 +162,6 @@ services: extra_hosts: - host.docker.internal:host-gateway - endorser-api: - pull_policy: missing - build: - context: ../services/endorser - dockerfile: Dockerfile - image: traction:endorser-api - depends_on: - endorser-agent: - condition: service_started - endorser-db: - condition: service_healthy - environment: - - POSTGRESQL_HOST=${ENDORSER_POSTGRESQL_HOST} - - POSTGRESQL_PORT=${POSTGRESQL_PORT} - - POSTGRESQL_DB=${ENDORSER_PSQL_DB} - - ENDORSER_API_ADMIN_USER=${ENDORSER_API_ADMIN_USER} - - ENDORSER_API_ADMIN_KEY=${ENDORSER_API_ADMIN_KEY} - - ACAPY_ADMIN_URL=${ENDORSER_ACAPY_ADMIN_URL} - - ACAPY_ADMIN_URL_API_KEY=${ENDORSER_ACAPY_ADMIN_URL_API_KEY} - - ENVIRONMENT=production - - TRACTION_WEBHOOK_URL=${ENDORSER_WEBHOOK_URL} - - ACAPY_WEBHOOK_URL_API_KEY=${ENDORSER_ACAPY_WEBHOOK_URL_API_KEY} - - ENDORSER_API_PORT=${ENDORSER_API_PORT} - ports: - - ${ENDORSER_SERVICE_PORT}:${ENDORSER_API_PORT} - volumes: - - ../services/endorser:/app:rw - extra_hosts: - - host.docker.internal:host-gateway - endorser-agent: image: ghcr.io/hyperledger/aries-cloudagent-python:py3.9-0.12.2 depends_on: @@ -234,58 +204,10 @@ services: extra_hosts: - host.docker.internal:host-gateway - endorser-db: - image: "postgres:14.5" - environment: - - POSTGRES_USER=${POSTGRESQL_USER} - - POSTGRES_PASSWORD=${POSTGRESQL_PASSWORD} - - POSTGRES_DB=${POSTGRESQL_DB} - ports: - - ${ENDORSER_POSTGRESQL_PORT}:5432 - volumes: - - endorser-wallet:/var/lib/postgresql/data - healthcheck: - test: ["CMD-SHELL", "pg_isready -U postgres"] - interval: 10s - timeout: 5s - retries: 5 - extra_hosts: - - host.docker.internal:host-gateway - - endorser-api-1: - pull_policy: missing - build: - context: ../services/endorser - dockerfile: Dockerfile - image: traction:endorser-api - depends_on: - endorser-agent-1: - condition: service_started - endorser-db-1: - condition: service_healthy - environment: - - POSTGRESQL_HOST=${ENDORSER_1_POSTGRESQL_HOST} - - POSTGRESQL_PORT=${POSTGRESQL_PORT} - - POSTGRESQL_DB=${ENDORSER_PSQL_DB} - - ENDORSER_API_ADMIN_USER=${ENDORSER_API_ADMIN_USER} - - ENDORSER_API_ADMIN_KEY=${ENDORSER_API_ADMIN_KEY} - - ACAPY_ADMIN_URL=${ENDORSER_1_ACAPY_ADMIN_URL} - - ACAPY_ADMIN_URL_API_KEY=${ENDORSER_ACAPY_ADMIN_URL_API_KEY} - - ENVIRONMENT=production - - TRACTION_WEBHOOK_URL=${ENDORSER_1_WEBHOOK_URL} - - ACAPY_WEBHOOK_URL_API_KEY=${ENDORSER_ACAPY_WEBHOOK_URL_API_KEY} - - ENDORSER_API_PORT=${ENDORSER_API_1_PORT} - ports: - - ${ENDORSER_1_SERVICE_PORT}:${ENDORSER_API_1_PORT} - volumes: - - ../services/endorser:/app:rw - extra_hosts: - - host.docker.internal:host-gateway - endorser-agent-1: image: ghcr.io/hyperledger/aries-cloudagent-python:py3.9-0.12.2 depends_on: - endorser-db-1: + endorser-db: condition: service_healthy ports: - ${ACAPY_ENDORSER_1_ADMIN_PORT}:${ACAPY_ENDORSER_1_ADMIN_PORT} @@ -305,7 +227,7 @@ services: --wallet-key '${ENDORSER_ACAPY_WALLET_ENCRYPTION_KEY}' \ --wallet-type '${ENDORSER_ACAPY_WALLET_TYPE}' \ --wallet-storage-type '${ENDORSER_ACAPY_WALLET_STORAGE_TYPE}' \ - --wallet-storage-config '{\"url\":\"${ENDORSER_1_POSTGRESQL_HOST}:5432\",\"max_connections\":5}' \ + --wallet-storage-config '{\"url\":\"${ENDORSER_POSTGRESQL_HOST}:5432\",\"max_connections\":5}' \ --wallet-storage-creds '{\"account\":\"${POSTGRESQL_USER}\",\"password\":\"${POSTGRESQL_PASSWORD}\",\"admin_account\":\"${POSTGRESQL_USER}\",\"admin_password\":\"${POSTGRESQL_PASSWORD}\"}' \ --wallet-name endorser-wallet-1 \ --seed '${ACAPY_ENDORSER_SEED_1}' \ @@ -324,16 +246,16 @@ services: extra_hosts: - host.docker.internal:host-gateway - endorser-db-1: + endorser-db: image: "postgres:14.5" environment: - POSTGRES_USER=${POSTGRESQL_USER} - POSTGRES_PASSWORD=${POSTGRESQL_PASSWORD} - POSTGRES_DB=${POSTGRESQL_DB} ports: - - ${ENDORSER_1_POSTGRESQL_PORT}:5432 + - ${ENDORSER_POSTGRESQL_PORT}:5432 volumes: - - endorser-wallet-1:/var/lib/postgresql/data + - endorser-wallet:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres"] interval: 10s diff --git a/services/endorser/.dockerignore b/services/endorser/.dockerignore deleted file mode 100644 index 91791376b..000000000 --- a/services/endorser/.dockerignore +++ /dev/null @@ -1,7 +0,0 @@ -Dockerfile -__pycache__/ -.idea/ -.tox/ -.coverage -tests/ -venv/ diff --git a/services/endorser/.gitignore b/services/endorser/.gitignore deleted file mode 100644 index b09671338..000000000 --- a/services/endorser/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -.idea -venv -node_modules -__pycache__ -.tox -.pytest_cache -*.egg-info -.coverage diff --git a/services/endorser/Dockerfile b/services/endorser/Dockerfile deleted file mode 100644 index 06be48607..000000000 --- a/services/endorser/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:3.10-slim-buster - -WORKDIR /app -ENV ENDORSER_API_PORT=5000 -COPY requirements.txt requirements.txt -RUN pip3 install -r requirements.txt - -COPY . . - -EXPOSE ${ENDORSER_API_PORT} -ENTRYPOINT ["./docker-entrypoint.sh"] \ No newline at end of file diff --git a/services/endorser/README.md b/services/endorser/README.md deleted file mode 100644 index 43d77ddbc..000000000 --- a/services/endorser/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Endorser Services - -Endorser services are built using [FastAPI](https://fastapi.tiangolo.com/). - -To install local dependencies: - -```shell -pip install -r requirements.txt -gunicorn -k uvicorn.workers.UvicornWorker -b localhost:5000 api.main:app -``` - -To run linting and tests locally (these are executed automatically for each PR): - -```shell -pip install tox -tox -e lint -tox -e test -``` diff --git a/services/endorser/alembic.ini b/services/endorser/alembic.ini deleted file mode 100644 index a7ae537af..000000000 --- a/services/endorser/alembic.ini +++ /dev/null @@ -1,36 +0,0 @@ -[alembic] -script_location = api/db/migrations - -[loggers] -keys = root,sqlalchemy,alembic - -[handlers] -keys = console - -[formatters] -keys = generic - -[logger_root] -level = WARN -handlers = console -qualname = - -[logger_sqlalchemy] -level = WARN -handlers = -qualname = sqlalchemy.engine - -[logger_alembic] -level = INFO -handlers = -qualname = alembic - -[handler_console] -class = StreamHandler -args = (sys.stderr,) -level = NOTSET -formatter = generic - -[formatter_generic] -format = %(levelname)-5.5s [%(name)s] %(message)s -datefmt = %H:%M:%S \ No newline at end of file diff --git a/services/endorser/api/acapy_utils.py b/services/endorser/api/acapy_utils.py deleted file mode 100644 index 6583b3868..000000000 --- a/services/endorser/api/acapy_utils.py +++ /dev/null @@ -1,157 +0,0 @@ -from aiohttp import ( - ClientSession, - ClientResponse, -) -import json -from fastapi import Request - -from api.core.config import settings - - -def get_acapy_headers(headers=None, tenant=False) -> dict: - """Return HTTP headers required for aca-py admin call.""" - - if not headers: - headers = {} - if not headers.get("accept"): - headers["accept"] = "application/json" - if not headers.get("Content-Type"): - headers["Content-Type"] = "application/json" - if settings.ACAPY_ADMIN_URL_API_KEY: - headers["X-API-Key"] = settings.ACAPY_ADMIN_URL_API_KEY - return headers - - -async def acapy_admin_request_from_request( - request: Request, -) -> dict: - body = None - try: - body = await request.json() - except Exception: - pass - path = request.url.path.replace("/tenant_acapy/", "") - resp_text = await acapy_admin_request( - request.method, - path, - data=body, - text=False, - params=request.query_params, - headers=None, - tenant=True, - ) - return resp_text - - -async def acapy_admin_request( - method, path, data=None, text=False, params=None, headers=None, tenant=False -) -> ClientResponse: - """ - Generic routine to call an Aca-Py admin api. - - Default headers are used if not supplied, and security headers are injected. - - Args: - method: http method (i.e. GET, POST, etc) - path: endpoint path (e.g. /multitenancy/wallet) - data: json object to POST (default None) - text: expect a plaintext response (default False which means json response) - params: dict of query params to include in request - headers: dict of headers to include in the request (default None) - tenant: whether request is in context of a tenant (default False) - - Returns: - aiohttp response object - """ - params = {k: v for (k, v) in (params or {}).items() if v is not None} - url = f"{settings.ACAPY_ADMIN_URL}/{path}" - - # TODO where should this live, and how do we want to handle HTTP sessions? - async with ClientSession() as client_session: - headers = get_acapy_headers(headers, tenant) - async with client_session.request( - method, - url, - json=data, - params=params, - headers=headers, - ) as resp: - resp_text = await resp.text() - try: - resp.raise_for_status() - except Exception as e: - # try to retrieve and print text on error - raise Exception(f"Error: {resp_text}") from e - if not resp_text and not text: - return None - if not text: - try: - return json.loads(resp_text) - except json.JSONDecodeError as e: - raise Exception(f"Error decoding JSON: {resp_text}") from e - return resp_text - - -async def acapy_GET(path, text=False, params=None, headers=None) -> ClientResponse: - """ - Call an Aca-Py tenant endpoint using GET method. - """ - - response = await acapy_admin_request( - "GET", path, data=None, text=text, params=params, headers=headers, tenant=True - ) - return response - - -async def acapy_POST( - path, data=None, text=False, params=None, headers=None -) -> ClientResponse: - """ - Call an Aca-Py tenant endpoint using POST method. - """ - - response = await acapy_admin_request( - "POST", path, data=data, text=text, params=params, headers=headers, tenant=True - ) - return response - - -async def acapy_PATCH(path, text=False, params=None, headers=None) -> ClientResponse: - """ - Call an Aca-Py tenant endpoint using PATCH method. - """ - - response = await acapy_admin_request( - "PATCH", path, data=None, text=text, params=params, headers=headers, tenant=True - ) - return response - - -async def acapy_PUT( - path, data=None, text=False, params=None, headers=None -) -> ClientResponse: - """ - Call an Aca-Py tenant endpoint using PUT method. - """ - - response = await acapy_admin_request( - "PUT", path, data=data, text=text, params=params, headers=headers, tenant=True - ) - return response - - -async def acapy_DELETE(path, text=False, headers=None) -> ClientResponse: - """ - Call an Aca-Py tenant endpoint using DELETE method. - """ - - response = await acapy_admin_request( - "DELETE", path, data=None, text=text, params=None, headers=headers, tenant=True - ) - return response - - -# TODO in case we need them, -# we have implemented these specific utility functions previously: -# async def admin_GET_FILE(self, path, params=None, headers=None) -> bytes: -# async def admin_PUT_FILE(self, files, url, params=None, headers=None) -> bytes: diff --git a/services/endorser/api/core/config.py b/services/endorser/api/core/config.py deleted file mode 100644 index 790019d09..000000000 --- a/services/endorser/api/core/config.py +++ /dev/null @@ -1,108 +0,0 @@ -import logging -import os -from enum import Enum -from functools import lru_cache -from typing import Optional - -from pydantic import BaseSettings, PostgresDsn - -logger = logging.getLogger(__name__) - - -class EnvironmentEnum(str, Enum): - PRODUCTION = "production" - LOCAL = "local" - - -class GlobalConfig(BaseSettings): - TITLE: str = "Endorser" - DESCRIPTION: str = "An endorser service for aca-py wallets" - - ENVIRONMENT: EnvironmentEnum - DEBUG: bool = False - TESTING: bool = False - TIMEZONE: str = "UTC" - - # the following defaults match up with default values in scripts/.env.example - # these MUST be all set in non-local environments. - PSQL_HOST: str = os.environ.get("ENDORSER_POSTGRESQL_HOST", "localhost") - PSQL_PORT: int = os.environ.get("ENDORSER_POSTGRESQL_PORT", 5432) - PSQL_DB: str = os.environ.get("ENDORSER_POSTGRESQL_DB", "traction") - - PSQL_USER: str = os.environ.get("ENDORSER_DB_USER", "tractionuser") - PSQL_PASS: str = os.environ.get("ENDORSER_DB_USER_PWD", "tractionPass") - - PSQL_ADMIN_USER: str = os.environ.get("ENDORSER_DB_ADMIN", "tractionadminuser") - PSQL_ADMIN_PASS: str = os.environ.get("ENDORSER_DB_ADMIN_PWD", "tractionadminPass") - - # application connection is async - # fmt: off - SQLALCHEMY_DATABASE_URI: PostgresDsn = ( - f"postgresql+asyncpg://{PSQL_USER}:{PSQL_PASS}@{PSQL_HOST}:{PSQL_PORT}/{PSQL_DB}" # noqa: E501 - ) - # migrations connection uses owner role and is synchronous - SQLALCHEMY_DATABASE_ADMIN_URI: PostgresDsn = ( - f"postgresql://{PSQL_ADMIN_USER}:{PSQL_ADMIN_PASS}@{PSQL_HOST}:{PSQL_PORT}/{PSQL_DB}" # noqa: E501 - ) - # fmt: on - - ACAPY_ADMIN_URL: str = os.environ.get( - "ENDORSER_ACAPY_ADMIN_URL", "http://localhost:9031" - ) - ACAPY_ADMIN_URL_API_KEY: str = os.environ.get( - "ENDORSER_ACAPY_ADMIN_URL_API_KEY", "change-me" - ) - - ENDORSER_API_ADMIN_USER: str = os.environ.get("ENDORSER_API_ADMIN_USER", "endorser") - ENDORSER_API_ADMIN_KEY: str = os.environ.get("ENDORSER_API_ADMIN_KEY", "change-me") - - ENDORSER_WEBHOOK_URL: str = os.environ.get( - "ENDORSER_WEBHOOK_URL", "http://endorser-api:5000/webhook" - ) - ACAPY_WEBHOOK_URL_API_KEY_NAME = "x-api-key" - ACAPY_WEBHOOK_URL_API_KEY: str = os.environ.get("ACAPY_WEBHOOK_URL_API_KEY", "") - - DB_ECHO_LOG: bool = False - - # Api V1 prefix - API_V1_STR = "/v1" - - # openssl rand -hex 32 - JWT_SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" - JWT_ALGORITHM = "HS256" - JWT_ACCESS_TOKEN_EXPIRE_MINUTES = 300 - - class Config: - case_sensitive = True - - -class LocalConfig(GlobalConfig): - """Local configurations.""" - - DEBUG: bool = True - ENVIRONMENT: EnvironmentEnum = EnvironmentEnum.LOCAL - - -class ProdConfig(GlobalConfig): - """Production configurations.""" - - DEBUG: bool = False - ENVIRONMENT: EnvironmentEnum = EnvironmentEnum.PRODUCTION - - -class FactoryConfig: - def __init__(self, environment: Optional[str]): - self.environment = environment - - def __call__(self) -> GlobalConfig: - if self.environment == EnvironmentEnum.LOCAL.value: - return LocalConfig() - return ProdConfig() - - -@lru_cache() -def get_configuration() -> GlobalConfig: - return FactoryConfig(os.environ.get("ENVIRONMENT"))() - - -settings = get_configuration() diff --git a/services/endorser/api/endorser_main.py b/services/endorser/api/endorser_main.py deleted file mode 100644 index dde867f78..000000000 --- a/services/endorser/api/endorser_main.py +++ /dev/null @@ -1,58 +0,0 @@ -from fastapi import APIRouter, Depends, FastAPI, HTTPException, status -from fastapi.security import OAuth2PasswordRequestForm, OAuth2PasswordBearer -from starlette.middleware import Middleware -from starlette_context import plugins -from starlette_context.middleware import RawContextMiddleware - -from api.endpoints.routes.endorser import router as endorser_router -from api.endpoints.dependencies.jwt_security import AccessToken, create_access_token -from api.core.config import settings as s - - -middleware = [ - Middleware( - RawContextMiddleware, - plugins=(plugins.RequestIdPlugin(), plugins.CorrelationIdPlugin()), - ), -] - -router = APIRouter() - - -def get_endorserapp() -> FastAPI: - application = FastAPI( - title=s.TITLE, - description=s.DESCRIPTION, - debug=s.DEBUG, - middleware=middleware, - ) - # mount the token endpoint - application.include_router(router, prefix="") - # mount other endpoints, these will be secured by the above token endpoint - application.include_router( - endorser_router, - prefix=s.API_V1_STR, - dependencies=[Depends(OAuth2PasswordBearer(tokenUrl="token"))], - tags=["endorser"], - ) - return application - - -@router.post("/token", response_model=AccessToken) -async def login_for_traction_api_admin( - form_data: OAuth2PasswordRequestForm = Depends(), -): - authenticated = await authenticate_innkeeper(form_data.username, form_data.password) - if not authenticated: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Incorrect Endorser Api Admin User or Endorser Api Admin Key", - headers={"WWW-Authenticate": "Bearer"}, - ) - return create_access_token(data={"sub": form_data.username}) - - -async def authenticate_innkeeper(username: str, password: str): - if s.ENDORSER_API_ADMIN_USER == username and s.ENDORSER_API_ADMIN_KEY == password: - return True - return False diff --git a/services/endorser/api/endpoints/dependencies/jwt_security.py b/services/endorser/api/endpoints/dependencies/jwt_security.py deleted file mode 100644 index 7beace336..000000000 --- a/services/endorser/api/endpoints/dependencies/jwt_security.py +++ /dev/null @@ -1,22 +0,0 @@ -from datetime import datetime, timedelta - -from jose import jwt -from pydantic import BaseModel - -from api.core.config import settings - - -class AccessToken(BaseModel): - access_token: str - token_type: str - - -def create_access_token(data: dict): - expires_delta = timedelta(minutes=settings.JWT_ACCESS_TOKEN_EXPIRE_MINUTES) - to_encode = data.copy() - expire = datetime.utcnow() + expires_delta - to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode( - to_encode, settings.JWT_SECRET_KEY, algorithm=settings.JWT_ALGORITHM - ) - return AccessToken(access_token=encoded_jwt, token_type="bearer") diff --git a/services/endorser/api/endpoints/routes/endorser.py b/services/endorser/api/endpoints/routes/endorser.py deleted file mode 100644 index 10580873d..000000000 --- a/services/endorser/api/endpoints/routes/endorser.py +++ /dev/null @@ -1,14 +0,0 @@ -import logging -from typing import List - -from fastapi import APIRouter -from starlette import status - -router = APIRouter() -logger = logging.getLogger(__name__) - - -@router.get("/transactions", status_code=status.HTTP_200_OK, response_model=List[dict]) -async def get_transactions() -> List[dict]: - # this should take some query params, sorting and paging params... - return [{}] diff --git a/services/endorser/api/endpoints/routes/webhooks.py b/services/endorser/api/endpoints/routes/webhooks.py deleted file mode 100644 index 7b8cc1146..000000000 --- a/services/endorser/api/endpoints/routes/webhooks.py +++ /dev/null @@ -1,101 +0,0 @@ -from enum import Enum -import logging - -from fastapi import APIRouter, Depends, FastAPI, HTTPException, Security -from fastapi.security.api_key import APIKeyHeader, APIKey -from starlette.status import HTTP_403_FORBIDDEN - -from api.core.config import settings -import api.acapy_utils as au - - -logger = logging.getLogger(__name__) - -router = APIRouter() - -api_key_header = APIKeyHeader( - name=settings.ACAPY_WEBHOOK_URL_API_KEY_NAME, auto_error=False -) - - -class WebhookTopicType(str, Enum): - ping = "ping" - connections = "connections" - oob_invitation = "oob-invitation" - connection_reuse = "connection-reuse" - connection_reuse_accepted = "connection-reuse-accepted" - basicmessages = "basicmessages" - issue_credential = "issue-credential" - issue_credential_v2_0 = "issue-credential-v2-0" - issue_credential_v2_0_indy = "issue-credential-v2-0-indy" - issue_credential_v2_0_ld_proof = "issue-credential-v2-0-ld-proof" - issuer_cred_rev = "issuer-cred-rev" - present_proof = "present-proof" - present_proof_v2_0 = "present-proof-v2-0" - endorse_transaction = "endorse_transaction" - revocation_registry = "revocation-registry" - revocation_notification = "revocation-notification" - problem_report = "problem-report" - - -async def get_api_key( - api_key_header: str = Security(api_key_header), -): - if api_key_header == settings.ACAPY_WEBHOOK_URL_API_KEY: - return api_key_header - else: - raise HTTPException( - status_code=HTTP_403_FORBIDDEN, detail="Could not validate credentials" - ) - - -def get_webhookapp() -> FastAPI: - application = FastAPI( - title="WebHooks", - description="Endpoints for Aca-Py WebHooks", - debug=settings.DEBUG, - middleware=None, - ) - application.include_router(router, prefix="") - return application - - -@router.post("/topic/{topic}/", response_model=dict) -async def process_webhook( - topic: WebhookTopicType, payload: dict, api_key: APIKey = Depends(get_api_key) -): - """Called by aca-py agent.""" - state = payload.get("state") - logger.info(f">>> Called webhook for endorser: {topic}/{state}") - if topic == "connections": - await setup_endorser_connection(payload) - return {} - - -async def setup_endorser_connection(payload: dict): - """Set endorser role on any connections we receive.""" - # TODO check final state for other connections protocols - if ( - payload["state"] == "completed" - and payload["connection_protocol"] == "didexchange/1.0" - ): - # confirm if we have already set the role on this connection - connection_id = payload["connection_id"] - conn_meta_data = await au.acapy_GET(f"connections/{connection_id}/metadata") - logger.info( - f">>> check for metadata on connection: {connection_id}: {conn_meta_data}" - ) - if "transaction-jobs" in conn_meta_data["results"]: - if "transaction_my_job" in conn_meta_data["results"]["transaction-jobs"]: - return - - # set our endorser role - logger.info(f">>> Setting meta-data for connection: {payload}") - params = {"transaction_my_job": "TRANSACTION_ENDORSER"} - await au.acapy_POST( - f"transactions/{connection_id}/set-endorser-role", params=params - ) - conn_meta_data = await au.acapy_GET(f"connections/{connection_id}/metadata") - logger.info( - f">>> re-check for metadata on connection: {connection_id}:{conn_meta_data}" - ) diff --git a/services/endorser/api/logging.conf b/services/endorser/api/logging.conf deleted file mode 100644 index b4e9be621..000000000 --- a/services/endorser/api/logging.conf +++ /dev/null @@ -1,33 +0,0 @@ -[loggers] -keys=root,simpleExample,sql - -[handlers] -keys=consoleHandler - -[formatters] -keys=simpleFormatter - -[logger_root] -level=INFO -handlers=consoleHandler - -[logger_sql] -level=ERROR -handlers=consoleHandler -qualname=sqlalchemy.engine -propagate=0 - -[logger_simpleExample] -level=DEBUG -handlers=consoleHandler -qualname=simpleExample -propagate=0 - -[handler_consoleHandler] -class=StreamHandler -level=DEBUG -formatter=simpleFormatter -args=(sys.stdout,) - -[formatter_simpleFormatter] -format=%(asctime)s - %(name)s - %(levelname)s - %(message)s \ No newline at end of file diff --git a/services/endorser/api/main.py b/services/endorser/api/main.py deleted file mode 100644 index 5cf47a2b0..000000000 --- a/services/endorser/api/main.py +++ /dev/null @@ -1,49 +0,0 @@ -import os -import time -import logging -from pathlib import Path - -import uvicorn -from fastapi import FastAPI - -from api.endpoints.routes.webhooks import get_webhookapp -from api.core.config import settings -from api.endorser_main import get_endorserapp - -# setup loggers -# TODO: set config via env parameters... -logging_file_path = (Path(__file__).parent / "logging.conf").resolve() -logging.config.fileConfig(logging_file_path, disable_existing_loggers=False) - -logger = logging.getLogger(__name__) - -os.environ["TZ"] = settings.TIMEZONE -time.tzset() - - -def get_application() -> FastAPI: - application = FastAPI( - title=settings.TITLE, - description=settings.DESCRIPTION, - debug=settings.DEBUG, - middleware=None, - ) - return application - - -app = get_application() -webhook_app = get_webhookapp() -app.mount("/webhook", webhook_app) - -endorser_app = get_endorserapp() -app.mount("/endorser", endorser_app) - - -@app.get("/", tags=["liveness"]) -def main(): - return {"status": "ok", "health": "ok"} - - -if __name__ == "__main__": - print("main.") - uvicorn.run(app, host="0.0.0.0", port=5300) diff --git a/services/endorser/docker-entrypoint.sh b/services/endorser/docker-entrypoint.sh deleted file mode 100755 index 3e8776a7d..000000000 --- a/services/endorser/docker-entrypoint.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -# python3 -m alembic upgrade head -# if [ $? == 0 ]; then - exec uvicorn api.main:app --host 0.0.0.0 --port $ENDORSER_API_PORT --log-level error -# fi -# echo 'Alembic db upgrade failed...' -# exit 1 diff --git a/services/endorser/requirements.txt b/services/endorser/requirements.txt deleted file mode 100644 index 7a14c07c0..000000000 --- a/services/endorser/requirements.txt +++ /dev/null @@ -1,32 +0,0 @@ -aiohttp~=3.9.5 -alembic==1.13.2 -anyio==3.7.1 -asgiref==3.8.1 -asyncpg==0.29.0 -certifi==2024.7.4 -click==8.1.7 -fastapi==0.111.1 -gunicorn==22.0.0 -h11==0.14.0 -httptools==0.6.1 -idna==3.7 -itsdangerous==2.2.0 -jose==1.0.0 -passlib==1.7.4 -psycopg2-binary==2.9.9 -pydantic==1.10.17 -python-jose[cryptography]==3.3.0 -python-multipart==0.0.9 -PyYAML==6.0.1 -requests==2.32.3 -sniffio==1.3.1 -SQLAlchemy==2.0.31 -sqlalchemy2-stubs==0.0.2a38 -sqlmodel==0.0.18 -starlette==0.37.2 -starlette-context==0.3.6 -urllib3==1.26.19 -uvicorn==0.30.1 -uvloop==0.19.0 -watchgod==0.8.2 -websockets==12.0 \ No newline at end of file diff --git a/services/endorser/tests/__init__.py b/services/endorser/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/services/endorser/tests/test_main.py b/services/endorser/tests/test_main.py deleted file mode 100644 index e6ef5c801..000000000 --- a/services/endorser/tests/test_main.py +++ /dev/null @@ -1,2 +0,0 @@ -def test_main(): - assert True diff --git a/services/endorser/tox.ini b/services/endorser/tox.ini deleted file mode 100644 index c653c318a..000000000 --- a/services/endorser/tox.ini +++ /dev/null @@ -1,29 +0,0 @@ -[flake8] -max-line-length = 88 -extend-ignore = E203 - -[tox] -skipsdist = True -envlist = py310 - -[testenv] -deps= - flake8 - pytest - -rrequirements.txt - black - -[testenv:lint] -skip_install = true -commands = - flake8 api - black api --diff --check - -[testenv:test] -skip_install = true -commands = - pytest tests - -[gh-actions] -python = - 3.10: py310 \ No newline at end of file