Skip to content
Snippets Groups Projects
Commit ae8024d2 authored by Steffen Schulze's avatar Steffen Schulze
Browse files

Merge branch 'chore/remove-aries-mediator' into 'main'

Removed Aries Mediator Service

See merge request eclipse/xfsc/ocm/ocm-engine!22
parents 0cbfbcb4 387942fd
No related branches found
No related tags found
No related merge requests found
Showing
with 0 additions and 7406 deletions
caddy
README.md
docker-compose.yml
.env
.env.sample
\ No newline at end of file
MEDIATOR_CONTROLLER_ADMIN_API_KEY=insecure-hello-world-1
MEDIATOR_AGENT_ADMIN_API_KEY=insecure-hello-world-2
MEDIATOR_ALIAS=MOON
LOG_LEVEL=INFO
MEDIATOR_ENDPOINT_URL=localhost:2015
# Aries Mediator Service
## TL;DR
This repository provides a simple process for a developer to run an Aries mediator agent. You should be able to bring the stack on-line by copying `.env.stample` to `.env` and running `docker-compose up`. For more information, keep reading.
## Build & Run
This is setup to be run as is with a simple `docker-compose up`. When run it will fire up the following containers:
### ngrok
You need to accept inbound connections. Most of us are behind firewalls or have impermanent IP addresses. Ngrok is used as a proxy to work around this. It will provide the URL that will act as a front door for your wallet to access the mediator service.
If you have a paid ngrok account you can provide your access token as one of the parameters (via the .env file). If not, leave it blank and it'll assume your on the free plan.
Pro Tip 🤓
- Free plans can only keep a connection open for 60 minutes. After this, you will need to restart the stack. If this gets annoying, use a paid plan for a long lived tunnel :)
- Every time your restart the stack (all the containers) the URL will change. You may be able to work around this with different paid plans.
### Caddy
Your wallet needs to open two connections to the mediator: The first is a standard **https** connection. This will be embedded in the invitation and will be used by the wallet for standard CRUD operations. Once the invite is accepted, a second WebSocket (wss) connection will be opened. This will be the primary mode of communication between the mediator and your wallet.
Caddy is used to route **http** and **wss** traffic to the correct transport on the mediator. Without it, two ngrok tunnels would need to be started making startup and configuration a little more complicated.
In any case, I think its more clear and consumable to have a single URL.
### Mediator Demo Controller
The mediator is configured to allow it to automatically accept connections. This functionality can be delegated to a controller process if business rules require approval / intervention before accepting a connection. A sample controller to do this is included with the project.
This custom **nodejs** app, written in TypeScript, uses [Feathers JS](https://feathersjs.com) to provide RESTFull endpoints to ACA-py. To enable the controller and have it determine if connections should be accepted:
1. Update the mediator configuration
In the `.env` file override the mediator config environment variable by adding `MEDIATOR_ARG_FILE` as follows:
```
MEDIATOR_ARG_FILE=./configs/mediator-with-controller.yml
```
2. Enable the mediator service in the docker stack
Remove these two lines from the [docker-compose.yml](./docker-compose.yml) file in the `mediator-controller` service:
```
profiles:
- donotstart
```
3. Add the following line to [start.sh](./acapy/start.sh) to allow the mediator to find and use the controller:
```
--webhook-url ${MEDIATOR_CONTROLLER_WEBHOOK}
```
### Mediator
A mediator is just a special type of agent. In this case, the mediator is ACA-py, with a few special config params, into make it run as a "mediator" rather than a traditional agent.
About 1/2 of the params for ACA-py are provided in `start.sh`, others are passed via a configuration file [mediator-auto-accept.yml](./acapy/configs/mediator.yml). Move them around as you see fit. Ones that are likely to change are better kept as environment variables.
### PostgreSQL
[PostgreSQL](https://www.postgresql.org) is well known RDBMS. It is used by the mediator persist wallet information. Without it, the wallet would be reset every time the stack is restarted. The first time the mediator container runs it will create a database for its wallet and initialize the wallet state.
### Run It !
0. Put some tunes on, it'll help. Here's one to get you started [Bossa Nova - Take On Me](https://open.spotify.com/track/7rpDM5zKuWaf2VzXFKU3yV?si=6aacebaa532d4848). You should have it up and running before the song is done.
1. Start by cloning this repo:
```console
git clone git@github.com:fullboar/aries-mediator-service.git
```
2. Copy the file `env.sample` to `.env` in the root of the project. The default values are fine, edit as you see fit. This file will be used by `docker-compose` to add or override any environment variables.
```console
cp env.sample .env
```
Pro Tip 🤓
You can generate strong tokens for production with `OpenSSL`:
```console
openssl rand 32 -hex
```
3. Bring up the stack. When you first run this command it will build the mediator container so it may take a few moments. Subsequent restarts will be much faster.
```console
docker-compose up
```
When the stack is on-line you'll see a big white QR code scroll up your screen, just above that is your invitation URL. I'll look something like this:
```console
mediator_1 | Invitation URL (Connections protocol):
mediator_1 | https://ed49-70-67-240-52.ngrok.io?c_i=eyJAdHlwZSI6ICJkaWQ6c292OkJ6Q2JzTlloTXJqSGlxWkRUVUFTSGc7c3BlYy9jb25uZWN0aW9ucy8xLjAvaW52aXRhdGlvbiIsICJAaWQiOiAiZmYwMjkzNmYtNzYzZC00N2JjLWE2ZmYtMmZjZmI2NmVjNTVmIiwgImxhYmVsIjogIk1lZGlhdG9yIiwgInJlY2lwaWVudEtleXMiOiBbIkFyVzd1NkgxQjRHTGdyRXpmUExQZERNUXlnaEhXZEJTb0d5amRCY0UzS0pEIl0sICJzZXJ2aWNlRW5kcG9pbnQiOiAiaHR0cHM6Ly9lZDQ5LTcwLTY3LTI0MC01Mi5uZ3Jvay5pbyJ9
```
The `c_i` parameter is your reusable invitation encoded as base64. Let's decode it and see what's inside:
```json
{
"@type": "did:sov:BzCbsNYhMrjHiqZDTUASHg;spec/connections/1.0/invitation",
"@id": "ff02936f-763d-47bc-a6ff-2fcfb66ec55f",
"label": "Mediator",
"recipientKeys": ["ArW7u6H1B4GLgrEzfPLPdDMQyghHWdBSoGyjdBcE3KJD"],
"serviceEndpoint": "https://ed49-70-67-240-52.ngrok.io"
}
```
Pro Tip 🤓
The invitation will be regenerated every time you restart the docker stack for two important reason:
1. The `ngrok` URL changes with restarts; and
2. The database is not persistent. This is where wallet initialization data, like [verkey](https://hyperledger.github.io/indy-did-method/) is stored. This will cause the `@id` and `recipientKeys` properties to change in the invitation (`c_i` payload above).
The general workaround steps are:
- expose the caddy ports outside of the container;
- start `ngrok` outside of a container and update the MEDIATOR_URL in [start.sh](./acapy/start.sh);
- give postgres a persistent volume;
### Aries Bifold Wallet Integration
You can easily use your newly minted mediator with the [Aries Bifold wallet](https://github.com/hyperledger/aries-mobile-agent-react-native). Take the full invitation URL from above and provide it to Bifold through the `MEDIATOR_URL` parameter. This can be in the form of an environment variable or, a more reliable way is to create a `.env` file in the root of the project with the parameter `MEDIATOR_URL` in it like this:
```console
MEDIATOR_URL=https://ed49-70-67-240-52.ngrok.io?c_i=eyJAdHlwZSI6ICJkaWQ6c292OkJ6Q2JzTlloTXJqSGlxWkRUVUFTSGc7c3BlYy9jb25uZWN0aW9ucy8xLjAvaW52aXRhdGlvbiIsICJAaWQiOiAiZmYwMjkzNmYtNzYzZC00N2JjLWE2ZmYtMmZjZmI2NmVjNTVmIiwgImxhYmVsIjogIk1lZGlhdG9yIiwgInJlY2lwaWVudEtleXMiOiBbIkFyVzd1NkgxQjRHTGdyRXpmUExQZERNUXlnaEhXZEJTb0d5amRCY0UzS0pEIl0sICJzZXJ2aWNlRW5kcG9pbnQiOiAiaHR0cHM6Ly9lZDQ5LTcwLTY3LTI0MC01Mi5uZ3Jvay5pbyJ9
```
## FAQ
### How does Bifold talk to the Mediator?
I struggled quite a bit with how HTTP/s and WSS are managed internally. The key, for me, was the `--endpoint` argument in ACA-py. To run a mediator, and maybe other agents, it takes two params for this argument. The first is the HTTP/s endpoint and the second is the `WSS` endpoint.
The HTTP/s endpoints, as per the docs on this param, will be used for invitations. Its going to be how your wallet finds and opens a dialogue with the mediator. Once a connection is established the WSS endpoint will be how the mediator and your wallet primarily communicated; they will message over the WebSocket.
### Can I use two URLs rather than one?
You can use two different URLs and route them to the respective ports on the mediator. It won't care. As per "How does Bifold talk to the Mediator" just make sure the HTTP/s port is the first in the `--endpoint` argument and use `wss://` ad the protocol in the second param even though the URL is the same.
I've used one URL and setup Caddy to route traffic to the correct port on the mediator. I think this setup is much more clear making it easier to consume and maintain.
### Are there other ways to manage transports?
Sure. There is a ACA-py plug-in that will allow it to take both HTTP/s and WSS traffic over a single port. You can find it in the [Plugin Toolbox](https://github.com/hyperledger/aries-acapy-plugin-toolbox)
My pro-tip is use Caddy. Reverse proxies are a tried and tru technology.
### Why Caddy?
I get asked a bit why Caddy? NGINX is great, but I find you need a PhD in NGINX to configure it. Caddy is lightweight and built from the ground up be more effective in cloud (k8s / OpenShift) deployments and has more human friendly config.
FROM bcgovimages/von-image:py36-1.16-1
USER root
RUN mkdir -p /acapy-mediator
WORKDIR /acapy-mediator
ADD https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64 /usr/bin/jq
RUN chmod +x /usr/bin/jq
USER $user
COPY acapy/requirements-latest.txt ./
RUN pip install -r ./requirements-latest.txt
# Copy the necessary files from the mediator sub-folder
COPY acapy/start.sh start.sh
RUN chmod +x start.sh
COPY acapy/configs configs
RUN aca-py --version > ./acapy-version.txt
ENTRYPOINT ["bash", "./start.sh"]
# This configuration is good for testing locally. It is not suited for
# production environments for the following reasons:
#
# 1. No persistent storage
# 2. Admin interface is not secured
# 3. Endpoint does not reflect a production endpoint
# 4. "Open mediation," or granting all incoming mediation requests, is enabled
# General
label: Mediator
endpoint: http://localhost:3000
inbound-transport:
- [http, 0.0.0.0, 3000]
outbound-transport: http
# Mediator does not use a ledger
no-ledger: true
# Admin
admin: [0.0.0.0, 3001]
admin-insecure-mode: true
# Connections
debug-connections: true
auto-accept-invites: true
auto-accept-requests: true
# Create and print multi-use invitation
connections-invite: true
invite-multi-use: true
# Mediation
open-mediation: true
enable-undelivered-queue: true
# General settings for mediator agent
# Mediator does not use a ledger
no-ledger: true
# Wallet
wallet-type: indy
wallet-name: mediator
wallet-key: insecure, for testing purposes only
auto-provision: true
# Mediation
open-mediation: true
enable-undelivered-queue: true
# Connections
debug-connections: true
auto-accept-invites: true
auto-accept-requests: true
auto-ping-connection: true
# Print an admin invite
connections-invite: true
invite-label: 'Mediator'
invite-multi-use: true
# General settings for mediator agent
# Mediator does not use a ledger
no-ledger: true
# Wallet
wallet-type: indy
wallet-name: mediator
wallet-key: insecure, for testing purposes only
auto-provision: true
# Mediation
open-mediation: true
enable-undelivered-queue: true
# Connections
debug-connections: true
auto-accept-requests: true
auto-ping-connection: true
# Print an admin invite
connections-invite: true
invite-label: 'Mediator'
invite-multi-use: true
# General
label: Indicio Mediator
inbound-transport:
- [acapy_plugin_toolbox.http_ws, 0.0.0.0, 3000]
outbound-transport: http
endpoint: http://localhost:3000/
# Mediator does not use a ledger
no-ledger: true
# Wallet
wallet-type: indy
wallet-name: mediator
# TODO: Replace this value with a secret stored outside of this repo
# This can be specified as an environment variable:
# ACAPY_WALLET_KEY=....
# TODO: Ensure this value matches provision.yml exactly
wallet-key: insecure, for testing purposes only
# Persistent Storage using postgres
#
# Available Wallet Schemes:
#
# DatabasePerWallet - each wallet has its own database
# MultiWalletSingleTable - all wallets are stored in single table in single
# database. Each wallet has its own connection pool.
# MultiWalletSingleTableSharedPool - all wallets are stored in single table in
# single database. The plugin will create only 1 connection pool reused by all
# wallets. This can be useful if intend to open many different wallets.
# Postgres has by default limitation of ~100 simultaneous connections and using
# this strategy you can limit number of DB connections significantly.
wallet-storage-type: postgres_storage
# TODO: Fill in these values as appropriate
# TODO: Ensure these values match provision.yml exactly
wallet-storage-config: '{"url":"localhost:5432", "wallet_scheme": "DatabasePerWallet"}'
wallet-storage-creds: '{"account":"acapy", "password":"acapy", "admin_account":"acapy", "admin_password":"acapy"}'
# Admin
# admin: [0.0.0.0, 3001]
# TODO: Replace this value with a secret stored outside of this repo
# This can be specified as an environment variable:
# ACAPY_ADMIN_API_KEY=....
# admin-api-key: 4QZoBE+lJZRGbWnq8ejL7FgFn9MCTr00OdDlSpNuN+4=
# Mediation
open-mediation: true
enable-undelivered-queue: true
# Connections
debug-connections: true
auto-accept-invites: true
auto-accept-requests: true
auto-ping-connection: true
# Toolbox Plugin
plugin:
- acapy_plugin_toolbox
# Print an admin invite
connections-invite: true
invite-metadata: '{"group": "admin"}'
invite-label: 'Mediator (Admin)'
invite-multi-use: true
# --label=Proof Mediator --inbound-transport=['acapy_plugin_toolbox.http_ws', '0.0.0.0', 3000] --outbound-transport=http --open-mediation=True --enable-undelivered-queue=True --debug-connections=True --auto-accept-invites=True --auto-accept-requests=True --auto-ping-connection=True --connections-invite=True --invite-metadata={"group": "admin"} --invite-label=Mediator (Admin) --invite-multi-use=True
# General
endpoint: http://localhost:3000/
# Mediator does not use a ledger
no-ledger: true
# Wallet
wallet-type: indy
wallet-name: mediator
# TODO: Replace this value with a secret stored outside of this repo
# This can be specified as an environment variable:
# ACAPY_WALLET_KEY=....
# TODO: Ensure this value matches provision.yml exactly
wallet-key: insecure, for testing purposes only
# Persistent Storage using postgres
#
# Available Wallet Schemes:
#
# DatabasePerWallet - each wallet has its own database
# MultiWalletSingleTable - all wallets are stored in single table in single
# database. Each wallet has its own connection pool.
# MultiWalletSingleTableSharedPool - all wallets are stored in single table in
# single database. The plugin will create only 1 connection pool reused by all
# wallets. This can be useful if intend to open many different wallets.
# Postgres has by default limitation of ~100 simultaneous connections and using
# this strategy you can limit number of DB connections significantly.
wallet-storage-type: postgres_storage
# TODO: Fill in these values as appropriate
# TODO: Ensure these values match provision.yml exactly
wallet-storage-config: '{"url":"localhost:5432", "wallet_scheme": "DatabasePerWallet"}'
wallet-storage-creds: '{"account":"acapy", "password":"acapy", "admin_account":"acapy", "admin_password":"acapy"}'
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
{
"env": {
"es6": true,
"node": true,
"jest": true
},
"parserOptions": {
"parser": "@typescript-eslint/parser",
"ecmaVersion": 2018,
"sourceType": "module"
},
"plugins": ["@typescript-eslint"],
"extends": ["plugin:@typescript-eslint/recommended"],
"rules": {
"indent": ["error", 2, { "SwitchCase": 1 }],
"linebreak-style": ["error", "unix"],
"quotes": ["error", "single", { "avoidEscape": true }],
"semi": ["error", "always"],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-empty-interface": "off"
}
}
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directory
# Commenting this out is preferred by some people, see
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git-
node_modules
# Users Environment Variables
.lock-wscript
# IDEs and editors (shamelessly copied from @angular/cli's .gitignore)
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
### Linux ###
*~
# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*
# KDE directory preferences
.directory
# Linux trash folder which might appear on any partition or disk
.Trash-*
# .nfs files are created when an open file is removed but is still being accessed
.nfs*
### OSX ###
*.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### Windows ###
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
# Others
lib/
data/
{
"singleQuote": true
}
# endorser-controller
> A controller for an instance of Aries Cloud Agent Python mediator agent
## About
This project uses [Feathers](http://feathersjs.com). An open source web framework for building modern real-time applications.
This code is borrowed from the [Aries VCR Issuer Agency/Endorser Controller](https://github.com/bcgov/aries-vcr-issuer-agency/tree/main/endorser)
## Getting Started
Getting up and running is as easy as 1, 2, 3.
1. Make sure you have [NodeJS](https://nodejs.org/) and [npm](https://www.npmjs.com/) installed.
2. Install your dependencies
```
cd path/to/mediator-controller
npm install
```
3. Start your app
```
npm start
```
## Testing
Simply run `npm test` and all your tests in the `test/` directory will be run.
## Scaffolding
Feathers has a powerful command line interface. Here are a few things it can do:
```
$ npm install -g @feathersjs/cli # Install Feathers CLI
$ feathers generate service # Generate a new Service
$ feathers generate hook # Generate a new Hook
$ feathers help # Show all commands
```
## Help
For more information on all the things you can do with Feathers visit [docs.feathersjs.com](http://docs.feathersjs.com).
{
"host": "localhost",
"port": "PORT",
"public": "../public/",
"paginate": {
"default": 10,
"max": 50
},
"authentication": {
"adminApiKey": "CONTROLLER_ADMIN_API_KEY"
},
"agent": {
"adminUrl": "MEDIATOR_ADMIN_URL",
"headers": {
"x-api-key": "MEDIATOR_ADMIN_API_KEY"
},
"alias": "MEDIATOR_ALIAS"
},
"logging": {
"logLevel": "LOG_LEVEL"
}
}
{
"host": "mediator-controller-app.feathersjs.com",
"port": "PORT"
}
{}
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
globals: {
'ts-jest': {
diagnostics: false,
},
},
};
source diff could not be displayed: it is too large. Options to address this: view the blob.
{
"name": "mediator-controller",
"description": "A controller for an instance of Aries Cloud Agent Python mediator agent",
"version": "0.0.0",
"homepage": "",
"private": true,
"main": "src",
"keywords": [
"feathers"
],
"author": {
"name": "Ian Costanzo",
"email": "iancostanzo@gmail.com"
},
"contributors": [
"Emiliano Suñé"
],
"bugs": {},
"directories": {
"lib": "src",
"test": "test/",
"config": "config/"
},
"engines": {
"node": "^14.0.0",
"npm": ">= 3.0.0"
},
"scripts": {
"test": "npm run lint && npm run compile && npm run jest",
"lint": "eslint src/. test/. --config .eslintrc.json --ext .ts --fix",
"dev": "ts-node-dev --no-notify src/",
"start": "npm run compile && node lib/",
"jest": "jest --forceExit",
"compile": "shx rm -rf lib/ && tsc"
},
"standard": {
"env": [
"jest"
],
"ignore": []
},
"types": "lib/",
"dependencies": {
"@feathersjs/configuration": "^4.5.11",
"@feathersjs/errors": "^4.5.11",
"@feathersjs/express": "^4.5.11",
"@feathersjs/feathers": "^4.5.11",
"@feathersjs/primus": "^4.5.11",
"@feathersjs/transport-commons": "^4.5.11",
"compression": "^1.7.4",
"cors": "^2.8.5",
"feathers-hooks-common": "^5.0.4",
"helmet": "^4.6.0",
"serve-favicon": "^2.5.0",
"winston": "^3.3.3",
"ws": "^7.5.6"
},
"devDependencies": {
"@types/compression": "^1.7.2",
"@types/cors": "^2.8.12",
"@types/jest": "^26.0.24",
"@types/serve-favicon": "^2.5.3",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"axios": "^0.21.4",
"eslint": "^7.32.0",
"jest": "^26.6.3",
"shx": "^0.3.4",
"ts-jest": "^26.5.6",
"ts-node-dev": "^1.1.8",
"typescript": "^4.5.5"
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment