Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • eclipse/xfsc/ocm/ocm-engine
  • zdravko61/ocm-engine
  • mjuergenscg/ocm-engine
  • tsabolov/ocm-engine
  • mikesell/ocm-engine
5 results
Show changes
Commits on Source (41)
Showing
with 2564 additions and 2343 deletions
......@@ -2,50 +2,22 @@ include:
- project: 'eclipse/xfsc/dev-ops/ci-templates'
file: 'helm-build-ci.yaml'
ref: main
- project: 'eclipsefdn/it/releng/gitlab-runner-service/gitlab-ci-templates'
file: '/jobs/buildkit.gitlab-ci.yml'
variables:
DOCKERFILE: Dockerfile
TAG: ${HARBOR_HOST}/${HARBOR_PROJECT}/$SERVICE
stages:
- build
- release
.rules:
rules:
- if: '$CI_COMMIT_TAG == null'
variables:
IMAGE_TAG_LOCATION: ${TAG}:${CI_COMMIT_BRANCH}
- if: '$CI_COMMIT_TAG != null'
variables:
IMAGE_TAG_LOCATION: ${TAG}:${CI_COMMIT_TAG}
docker-build:
extends: .buildkit
parallel:
matrix:
- SERVICE: [connection-manager, credential-manager,did-manager,proof-manager,ssi-abstraction,schema-manager]
rules:
- !reference [.rules, rules]
- SERVICE: [connection-manager, credential-manager,did-manager,proof-manager,ssi-abstraction,schema-manager,tenant-manager]
stage: build
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
script:
- echo "Project name is ${CI_PROJECT_NAME}"
- echo "CommitBranch is ${CI_COMMIT_BRANCH}"
- echo "Current Commit Tag:${CI_COMMIT_TAG}"
- echo "Current Service:${SERVICE}"
- echo "Used Tag:${IMAGE_TAG_LOCATION}"
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"${HARBOR_HOST}\":{\"auth\":\"$(echo -n ${HARBOR_USERNAME}:${HARBOR_PASSWORD} | base64)\"}}}" > /kaniko/.docker/config.json
- /kaniko/executor
--context "${CI_PROJECT_DIR}"
--dockerfile "${CI_PROJECT_DIR}/$DOCKERFILE"
--cache=true
--cache-ttl=24h
--destination "${IMAGE_TAG_LOCATION}"
--build-arg RUNNER_VERSION=${RUNNER_VERSION} --build-arg GITLAB_TOKEN=gitlab-ci-token:${CI_JOB_TOKEN}
--build-arg "SERVICE=${SERVICE}"
${KANIKO_PROXY_ARGS}
variables:
CI_REGISTRY: ${HARBOR_HOST}
CI_REGISTRY_USER: ${HARBOR_USERNAME}
CI_REGISTRY_PASSWORD: ${HARBOR_PASSWORD}
CI_REGISTRY_IMAGE: ${HARBOR_HOST}/${HARBOR_PROJECT}/$SERVICE
BUILD_ARG: "--opt build-arg:SERVICE=${SERVICE}"
......@@ -6,6 +6,7 @@
!*.d.ts
!*.mts
!jest.config.js
!*.json
# .. also in subdirectories
!*/
......
FROM node:20 AS dependencies
FROM node:20.11 AS dependencies
ARG APP_HOME=/home/node/app
ARG SERVICE
WORKDIR ${APP_HOME}
WORKDIR /home/node/app
RUN corepack enable
......@@ -12,7 +12,7 @@ COPY apps/shared/package.json ./apps/shared/
RUN pnpm install --frozen-lockfile
# Build shared
FROM node:20 as build-shared
FROM node:20.11 as build-shared
ARG APP_HOME=/home/node/app
ARG SERVICE
......@@ -22,14 +22,14 @@ WORKDIR ${APP_HOME}
RUN corepack enable
COPY apps/shared ./apps/shared
COPY --from=dependencies ${APP_HOME}/package.json ${APP_HOME}/pnpm-lock.yaml ${APP_HOME}/pnpm-workspace.yaml ${APP_HOME}/tsconfig*.json ${APP_HOME}/.swcrc ./
COPY --from=dependencies ${APP_HOME}/node_modules ./node_modules
COPY --from=dependencies ${APP_HOME}/apps/shared/node_modules ./apps/shared/node_modules
COPY --from=dependencies ${APP_HOME}/patches ./patches
COPY --from=dependencies /home/node/app/package.json /home/node/app/pnpm-lock.yaml /home/node/app/pnpm-workspace.yaml /home/node/app/tsconfig*.json /home/node/app/.swcrc ./
COPY --from=dependencies /home/node/app/node_modules ./node_modules
COPY --from=dependencies /home/node/app/apps/shared/node_modules ./apps/shared/node_modules
COPY --from=dependencies /home/node/app/patches ./patches
RUN pnpm --filter shared build
# Build service
FROM node:20 AS build-service
FROM node:20.11 AS build-service
ARG APP_HOME=/home/node/app
ARG SERVICE
......@@ -38,26 +38,25 @@ WORKDIR ${APP_HOME}
RUN corepack enable
COPY --from=dependencies ${APP_HOME}/package.json ${APP_HOME}/pnpm-lock.yaml ${APP_HOME}/pnpm-workspace.yaml ${APP_HOME}/tsconfig*.json ${APP_HOME}/.swcrc ./
COPY --from=dependencies ${APP_HOME}/node_modules ./node_modules
COPY --from=dependencies ${APP_HOME}/patches ./patches
COPY --from=build-shared ${APP_HOME}/apps/shared ./apps/shared
COPY --from=dependencies /home/node/app/package.json /home/node/app/pnpm-lock.yaml /home/node/app/pnpm-workspace.yaml /home/node/app/tsconfig*.json /home/node/app/.swcrc ./
COPY --from=dependencies /home/node/app/node_modules ./node_modules
COPY --from=dependencies /home/node/app/patches ./patches
COPY --from=build-shared /home/node/app/apps/shared ./apps/shared
COPY apps/${SERVICE} ./apps/${SERVICE}
RUN pnpm install --frozen-lockfile && pnpm --filter ${SERVICE} build && pnpm --filter ${SERVICE} --prod deploy build
# Final
FROM node:20-slim AS final
FROM node:20.11-slim AS final
ARG APP_HOME=/home/node/app
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}
WORKDIR ${APP_HOME}
WORKDIR /home/node/app
CMD ["node", "dist/main.js"]
COPY --from=build-service --chown=node:node ${APP_HOME}/build/dist ./dist
COPY --from=build-service --chown=node:node ${APP_HOME}/build/node_modules ./node_modules
COPY --from=build-service --chown=node:node ${APP_HOME}/build/package.json .
COPY --from=build-service --chown=node:node /home/node/app/build/dist ./dist
COPY --from=build-service --chown=node:node /home/node/app/build/node_modules ./node_modules
COPY --from=build-service --chown=node:node /home/node/app/build/package.json .
# Cut unnecessary stuff from package.json. Only leave name, version, description and module type
RUN node -e "\
......
This diff is collapsed.
# Organizational Credential Manager (v2)
# Organization Credential Manager (OCM)
## Overview
## Introduction
OCM (Organizational Credential Manager) is a Node.js-based microservice system designed to manage organizational credentials.
Organization Credential Manager (OCM) is a comprehensive suite of microservices designed to facilitate the management of digital credentials within an organizational context. Utilizing the principles of Self-Sovereign Identity (SSI), OCM leverages a series of components to enable secure, efficient handling of credentials, keys, and connections between entities.
## Prerequisites
## Components
* Node.js (version 20 or later)
* pnpm
* Docker and Docker Compose for local development
OCM is comprised of several key microservices, each serving a specific role within the credential management ecosystem:
## Installation
### [SSI Abstraction](apps/ssi-abstraction/README.md)
A wrapper around the Credo library ([Credo](https://credo.js.org)), formerly known as Aries Framework Javascript, an implementation of a Hyperledger Indy Agent in TypeScript. This service abstracts the complexities of SSI operations for other components.
1. Clone the repository:
### [Tenant Manager](apps/tenant-manager/README.md)
Manages the creation and listing of OCM tenants, with each tenant maintaining their collections of credentials, keys, etc. This service acts as a critical interface to the SSI Abstraction functionality and is intended for administrative use only.
```bash
git clone https://gitlab.eclipse.org/eclipse/xfsc/ocm/ocm-engine.git
```
### [DID Manager](apps/did-manager/README.md)
Provides API functions for registering Decentralized Identifiers (DIDs) on the Indy Ledger and resolving existing DID Documents, facilitating secure identity verification and management.
2. Navigate to the repository directory:
### [Connection Manager](apps/connection-manager/README.md)
Facilitates the establishment of connections between OCM tenants using Aries protocols, enabling secure, verified interactions.
```bash
cd ocm-engine
```
### [Schema Manager](apps/schema-manager/README.md)
Allows tenants to manage Indy Schemas and Credential Definitions, laying the groundwork for the creation and recognition of standardized credential formats.
3. Install dependencies:
### [Credential Manager](apps/credential-manager/README.md)
Offers an API for the detailed management of tenant credentials, streamlining the process of issuing, holding, and verifying digital credentials.
```bash
pnpm i
```
### [Proof Manager](apps/proof-manager/README.md)
Enables tenants to create proof requests, an essential feature for the verification of credential authenticity and integrity.
4. Start the services locally:
## Deployment
```bash
pnpm -F ssi-abstraction start
pnpm -F connection-manager start
...
```
### Kubernetes
5. Or start the whole stack in Docker Compose:
OCM can be deployed within a Kubernetes cluster to leverage the benefits of container orchestration for managing and scaling the microservices efficiently. The deployment process is streamlined through the use of Helm, a package manager for Kubernetes that facilitates the installation, upgrade, and management of Kubernetes applications.
```bash
docker compose up -d
```
Each microservice within OCM is equipped with its own Helm chart located in the service's folder. These Helm charts define the Kubernetes resources required for deploying and running the service, including Deployments, Services, and any necessary ConfigMaps or Secrets.
6. Create a new tenant:
### Docker Compose (Local)
```bash
pnpm createTenant [tenantName]
```
For local development and testing purposes, the OCM stack can also be run using Docker Compose with the following command:
Desired label for the new tenant could be set with `tenantName`.
```bash
docker compose up -d
```
## Example Flows (OCM Usage)
This command builds the service container images and starts the stack. It's a convenient way to quickly bring up the OCM environment on a local machine for development, testing, or demonstration purposes.
Please refer to [OCM-flow-overview](documentation/ocm-flow-overview.md)
#### Starting multiple instances of OCM
To demonstrate
```bash
./scripts/start_instance.sh
```
> This command can be run multiple times to start several instances of OCM.
> To stop instances that were started using the above command, use `./scripts/stop_instance.sh`.
## Local Development
To run each service locally, the following prerequisites are needed:
- Node.js (installed on the local machine)
- pnpm (package manager)
- Docker Compose (for running NATS server and S3 storage)
Before starting a service, create a `.env` file in the service's directory based on the `.env.example` provided, renaming it to `.env`.
## Documentation and Example Flows
For detailed usage and example flows, please refer to the [Postman Collection](documentation/Gaia-X_Organization_Credential_Manager.postman_collection.json) and the [OCM Example Flows](documentation/ocm-example-flows.md).
## Security
Note: Authentication and Authorization mechanisms are considered outside the scope of this project and should be addressed at the infrastructure level or through other means.
## License
This project is licensed under the [Apache 2.0 License](LICENSE)
Licensed under the Apache 2.0 License ([LICENSE](LICENSE)).
# GDPR Compliance Document
The objective of this document is to detail, the data being stored and proccessed by the Organization Credential Manager's, Connection Manger.
## What information is stored
### Source User Information
The email id received from the user.
### Technical User Information (Public)
- DID of the OCM agent
- DID of the other participant in the connection
- Connection Status
- Connection Internal Ids
- Date created and updated
- Holder email as well as wallet name is stored in DB
## How is the information stored
The Source User Information and Technical User Information is encrypted using the Private Key of the Organizations SSI Agent and stored internally (on the agent) on PostgreSQL and externally/ metadata (shared between the OCM services) on PostgreSQL of Organization.
## Who can access the information
The Source User Information and Technical User Information both are accessible only by the Organization specific SSI agent's private key.
## How long will the information stay
The Source User Information and Technical User Information is wiped out according to the retention periods (not defined yet).
This diff is collapsed.
# OCM Connection Manager
## Description
<hr/>
The connection manager is the microservice responsible for handling the features related to connection between aries agents.
The service implements REST endpoints, events and calls to other services related to connections in the Organizational Credential Manager.
#### Security note
`Man in the mid` security concern will be address in Phase II of of the project. It was discussed multiple times, and one of the options is to use [TRAIN API](https://train.trust-scheme.de/info/) .
## Introduction
The OCM Connection Manager API enables you to:
- Create and accept invitations
- Create self-connections
- List all connections
- Retrieve a connection by ID
- Block connections
## Prerequisites
Ensure you have Node.js installed ([official Node.js website](https://nodejs.org)).
## Configuration
Set configuration via environment variables or an `.env` file:
| Property | Description | Default |
|---|---|---|
| `HTTP_HOSTNAME` | HTTP server hostname | `0.0.0.0` |
| `HTTP_PORT` | HTTP server port | `3000` |
| `NATS_URL` | NATS Server URL | `nats://localhost:4222` |
| `NATS_USER` | NATS user | |
| `NATS_PASSWORD` | NATS password | |
| `NATS_MONITORING_URL` | NATS Monitoring URL | `http://localhost:8222` |
## Usage
<hr/>
### Swagger Documentation:
[Swagger/OpenAPI](swagger.json)
## Installation
<hr/>
### Pre-requisites
- pnpm
- docker
- docker-compose
- postgres
- NATS Server
### OCM Services Dependencies
- SSI Abstraction
- Principal Manager
- Attestation Manager
- Proof Manager
## Running the app
<hr/>
**Each service in the Organizational Credential Manager can be run from the infrastructure repository with Docker.**
**The .env files are in the infrastructure repository under /env**
```bash
## production:
./deployment/ci
## development:
./deployment/dev
```
- (optional) Edit docker-compose.yml in "infrastructure" to use either **/ci/** or **/dev/** Dockerfiles.
- Run while in **"infrastructure"** project:
Start in development mode:
```bash
$ docker-compose up --build conn-m
pnpm start
```
to run only Connection Manager or
### Operations
> **Note:** All requests need a `tenantId` query parameter.
#### Create an Invitation
```bash
$ docker-compose up --build
```
to run all the services.
### Environment variables required
```
1. PORT
2. DATABASE_URL
3. NATS_URL
4. AGENT_URL
```
### Outgoing communication services
curl -X POST http://ocm-indy.xfsc.dev/v1/invitations?tenantId=<tenantId>
```
1. PRINCIPAL MANAGER
2. ATTESTATION MANAGER
3. PROOF MANAGER
Response:
```json
{
"status": 201,
"data": {
"invitationUrl": "http://ocm-indy.xfcs.dev?oob=..."
}
}
```
### Incoming communication services
```
1. SSI-ABSTRACTION
2. PROOF MANAGER
3. ATTESTATION MANAGER
```
### Supported features
```
1. Nats endpoint to update connection status
2. Create invitation URL.
3. Provide connection information.
4. Provide a list of connections.
5. Nats endpoint to get connection by ID.
6. Nats endpoint to make connection trusted.
7. Accept connection invitation.
#### Accept an Invitation
```bash
curl -X POST -d '{"invitationUrl":"..."}' http://ocm-indy.xfsc.dev/v1/invitations/accept?tenantId=<tenantId>
```
## Test
<hr/>
#### Create a Self-Connection
```bash
# unit tests
$ pnpm test
# e2e tests
$ pnpm test:e2e
# test coverage
$ pnpm test:cov
curl -X POST http://ocm-indy.xfsc.dev/v1/connections?tenantId=<tenantId>
```
## GDPR
<hr/>
[GDPR](GDPR.md)
## Dependencies
<hr/>
[Dependencies](package.json)
## API Reference
For detailed documentation, refer to the [OpenAPI Specification](openapi.json).
## License
<hr/>
[Apache 2.0 license](LICENSE)
Licensed under the Apache 2.0 License ([LICENSE](LICENSE)).
{
"openapi": "3.0.0",
"paths": {
"/v1/connections": {
"get": {
"operationId": "ConnectionsController_getAll",
"summary": "Fetch a list of connections",
"description": "This call provides a list of connections for a given tenant",
"parameters": [
{
"name": "tenantId",
"required": true,
"in": "query",
"description": "Specifies the tenant ID",
"schema": { "type": "string" }
}
],
"responses": {
"200": {
"description": "Connections fetched successfully",
"content": {
"application/json": {
"schema": {},
"examples": {
"Connections fetched successfully": {
"value": {
"statusCode": 200,
"message": "Connections fetched successfully",
"data": []
}
}
}
}
}
},
"404": {
"description": "Tenant not found",
"content": {
"application/json": {
"schema": {},
"examples": {
"Tenant not found": {
"value": {
"statusCode": 404,
"message": "Tenant not found",
"data": null
}
}
}
}
}
},
"500": {
"description": "Internal server error",
"content": {
"application/json": {
"schema": {},
"examples": {
"Internal server error": {
"value": {
"statusCode": 500,
"message": "Internal server error",
"data": null
}
}
}
}
}
}
},
"tags": ["Connections"]
},
"post": {
"operationId": "ConnectionsController_createWithSelf",
"summary": "Create a connection",
"description": "This call creates a self connection for a given tenant",
"parameters": [
{
"name": "tenantId",
"required": true,
"in": "query",
"description": "Specifies the tenant ID",
"schema": { "type": "string" }
}
],
"responses": {
"201": {
"description": "Connection created successfully",
"content": {
"application/json": {
"schema": {},
"examples": {
"Connection created successfully": {
"value": {
"statusCode": 201,
"message": "Connection created successfully",
"data": {}
}
}
}
}
}
},
"404": {
"description": "Tenant not found",
"content": {
"application/json": {
"schema": {},
"examples": {
"Tenant not found": {
"value": {
"statusCode": 404,
"message": "Tenant not found",
"data": null
}
}
}
}
}
},
"500": {
"description": "Internal server error",
"content": {
"application/json": {
"schema": {},
"examples": {
"Internal server error": {
"value": {
"statusCode": 500,
"message": "Internal server error",
"data": null
}
}
}
}
}
}
},
"tags": ["Connections"]
}
},
"/v1/connections/{connectionId}": {
"get": {
"operationId": "ConnectionsController_getById",
"summary": "Fetch a connection by ID",
"description": "This call provides a connection for a given tenant and connection ID",
"parameters": [
{
"name": "connectionId",
"required": true,
"in": "path",
"description": "The connection ID",
"example": "71b784a3",
"schema": { "type": "string" }
},
{
"name": "tenantId",
"required": true,
"in": "query",
"description": "Specifies the tenant ID",
"schema": { "type": "string" }
}
],
"responses": {
"200": {
"description": "Connection fetched successfully",
"content": {
"application/json": {
"schema": {},
"examples": {
"Connection fetched successfully": {
"value": {
"statusCode": 200,
"message": "Connection fetched successfully",
"data": {}
}
}
}
}
}
},
"404": {
"description": "Connection not found",
"content": {
"application/json": {
"schema": {},
"examples": {
"Tenant not found": {
"value": {
"statusCode": 404,
"message": "Tenant not found",
"data": null
}
},
"Connection not found": {
"value": {
"statusCode": 404,
"message": "Connection not found",
"data": null
}
}
}
}
}
},
"500": {
"description": "Internal server error",
"content": {
"application/json": {
"schema": {},
"examples": {
"Internal server error": {
"value": {
"statusCode": 500,
"message": "Internal server error",
"data": null
}
}
}
}
}
}
},
"tags": ["Connections"]
}
},
"/v1/connections/{idOrDid}/block": {
"post": {
"operationId": "ConnectionsController_block",
"summary": "Block a connection",
"description": "This call blocks a connection for a given tenant and connection ID",
"parameters": [
{
"name": "idOrDid",
"required": true,
"in": "path",
"description": "The connection ID or DID",
"example": "8d74c6ec-fa3e-4a09-91fb-5fd0062da835",
"schema": { "type": "string" }
},
{
"name": "tenantId",
"required": true,
"in": "query",
"description": "Specifies the tenant ID",
"schema": { "type": "string" }
}
],
"responses": {
"200": {
"description": "Connection blocked successfully",
"content": {
"application/json": {
"schema": {},
"examples": {
"Connection blocked successfully": {
"value": {
"statusCode": 200,
"message": "Connection blocked successfully",
"data": {}
}
}
}
}
}
},
"404": {
"description": "Connection not found",
"content": {
"application/json": {
"schema": {},
"examples": {
"Tenant not found": {
"value": {
"statusCode": 404,
"message": "Tenant not found",
"data": null
}
},
"Connection not found": {
"value": {
"statusCode": 404,
"message": "Connection not found",
"data": null
}
}
}
}
}
},
"500": {
"description": "Internal server error",
"content": {
"application/json": {
"schema": {},
"examples": {
"Internal server error": {
"value": {
"statusCode": 500,
"message": "Internal server error",
"data": null
}
}
}
}
}
}
},
"tags": ["Connections"]
}
},
"/v1/invitations": {
"post": {
"operationId": "InvitationsController_createInvitation",
"summary": "Create a new invitation",
"description": "This call creates a new invitation for a given tenant",
"parameters": [
{
"name": "tenantId",
"required": true,
"in": "query",
"description": "Specifies the tenant ID",
"schema": { "type": "string" }
}
],
"responses": {
"200": {
"description": "Invitation created successfully",
"content": {
"application/json": {
"schema": {},
"examples": {
"Invitation created successfully": {
"value": {
"statusCode": 200,
"message": "Invitation created successfully",
"data": {
"invitationUrl": "https://example.com/invitation"
}
}
}
}
}
}
},
"404": {
"description": "Tenant not found",
"content": {
"application/json": {
"schema": {},
"examples": {
"Tenant not found": {
"value": {
"statusCode": 404,
"message": "Tenant not found",
"data": null
}
}
}
}
}
},
"500": {
"description": "Failed to create invitation",
"content": {
"application/json": {
"schema": {},
"examples": {
"Failed to create invitation": {
"value": {
"statusCode": 500,
"message": "Failed to create invitation",
"data": null
}
}
}
}
}
}
},
"tags": ["Invitations"]
}
},
"/v1/invitations/receive": {
"post": {
"operationId": "InvitationsController_receiveInvitation",
"summary": "Receive an invitation",
"description": "This call receives an invitation for a given tenant",
"parameters": [
{
"name": "tenantId",
"required": true,
"in": "query",
"description": "Specifies the tenant ID",
"schema": { "type": "string" }
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ReceiveInvitationPayload"
}
}
}
},
"responses": {
"200": {
"description": "Invitation received successfully",
"content": {
"application/json": {
"schema": {},
"examples": {
"Invitation received successfully": {
"value": {
"statusCode": 200,
"message": "Invitation received successfully",
"data": { "connectionId": "123" }
}
}
}
}
}
},
"404": {
"description": "Tenant not found",
"content": {
"application/json": {
"schema": {},
"examples": {
"Tenant not found": {
"value": {
"statusCode": 404,
"message": "Tenant not found",
"data": null
}
}
}
}
}
},
"500": {
"description": "Failed to receive invitation",
"content": {
"application/json": {
"schema": {},
"examples": {
"Failed to receive invitation": {
"value": {
"statusCode": 500,
"message": "Failed to receive invitation",
"data": null
}
}
}
}
}
}
},
"tags": ["Invitations"]
}
}
},
"info": {
"title": "Gaia-X OCM Connection Manager",
"description": "",
"version": "1.0.0",
"contact": {}
},
"tags": [],
"servers": [],
"components": {
"schemas": {
"ReceiveInvitationPayload": {
"type": "object",
"properties": {
"invitationUrl": {
"type": "string",
"description": "The invitation URL to receive",
"example": "https://example.com/invitation"
}
},
"required": ["invitationUrl"]
}
}
}
}
......@@ -2,7 +2,9 @@
"name": "@ocm/connection-manager",
"version": "1.0.0",
"description": "Gaia-X OCM Connection Manager",
"author": "Gaia-X",
"contributors": [
"Berend Sliedrecht <berend@animo.id>",
"Konstantin Tsabolov <konstantin.tsabolov@spherity.com>"
],
"private": true,
......
import type { OnApplicationBootstrap } from '@nestjs/common';
import type {
MiddlewareConsumer,
NestModule,
OnApplicationBootstrap,
} from '@nestjs/common';
import type { ConfigType } from '@nestjs/config';
import { Inject, Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { RouterModule } from '@nestjs/core';
import { ClientProxy, ClientsModule, Transport } from '@nestjs/microservices';
import { HealthModule, OpenTelemetryModule } from '@ocm/shared';
import {
HealthModule,
OpenTelemetryModule,
loggerMiddleware,
} from '@ocm/shared';
import { NATS_CLIENT } from './common/constants.js';
import { httpConfig } from './config/http.config.js';
......@@ -73,7 +81,7 @@ import { InvitationsModule } from './invitations/invitations.module.js';
]),
],
})
export class Application implements OnApplicationBootstrap {
export class Application implements OnApplicationBootstrap, NestModule {
public constructor(
@Inject(NATS_CLIENT) private readonly client: ClientProxy,
) {}
......@@ -81,4 +89,8 @@ export class Application implements OnApplicationBootstrap {
public async onApplicationBootstrap(): Promise<void> {
await this.client.connect();
}
public configure(consumer: MiddlewareConsumer) {
consumer.apply(loggerMiddleware).forRoutes('*');
}
}
......@@ -5,7 +5,7 @@ import type {
} from '@ocm/shared';
import type { Observable } from 'rxjs';
import { Inject, Injectable } from '@nestjs/common';
import { Inject, Injectable, Logger } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import {
EventDidcommConnectionsBlock,
......@@ -19,6 +19,8 @@ import { NATS_CLIENT } from '../common/constants.js';
@Injectable()
export class ConnectionsService {
private readonly logger = new Logger(this.constructor.name);
public constructor(
@Inject(NATS_CLIENT) private readonly natsClient: ClientProxy,
) {}
......@@ -26,6 +28,10 @@ export class ConnectionsService {
public getAllConnections(
tenantId: string,
): Observable<EventDidcommConnectionsGetAll['data']> {
this.logger.log({
message: 'Request all connections',
labels: { tenantId },
});
return this.natsClient
.send<
EventDidcommConnectionsGetAll,
......@@ -36,19 +42,28 @@ export class ConnectionsService {
public getConnectionById(
tenantId: string,
id: string,
connectionId: string,
): Observable<EventDidcommConnectionsGetById['data']> {
this.logger.log({
message: 'Request a connection by ID',
labels: { tenantId },
'ocm.connections.connectionId': connectionId,
});
return this.natsClient
.send<
EventDidcommConnectionsGetById,
EventDidcommConnectionsGetByIdInput
>(EventDidcommConnectionsGetById.token, { tenantId, id })
>(EventDidcommConnectionsGetById.token, { tenantId, id: connectionId })
.pipe(map((result) => result.data));
}
public createConnectionWithSelf(
tenantId: string,
): Observable<EventDidcommConnectionsCreateWithSelf['data']> {
this.logger.log({
message: 'Create connection with self',
labels: { tenantId },
});
return this.natsClient
.send<EventDidcommConnectionsCreateWithSelf>(
EventDidcommConnectionsCreateWithSelf.token,
......@@ -61,6 +76,11 @@ export class ConnectionsService {
tenantId: string,
idOrDid: string,
): Observable<EventDidcommConnectionsBlock['data']> {
this.logger.log({
message: 'Block a connection',
labels: { tenantId },
'ocm.connections.idOrDid': idOrDid,
});
return this.natsClient
.send<
EventDidcommConnectionsBlock,
......
......@@ -4,7 +4,7 @@ import type {
} from '@ocm/shared';
import type { Observable } from 'rxjs';
import { Inject, Injectable } from '@nestjs/common';
import { Inject, Injectable, Logger } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import {
EventDidcommConnectionsCreateInvitation,
......@@ -16,6 +16,8 @@ import { NATS_CLIENT } from '../common/constants.js';
@Injectable()
export class InvitationsService {
private readonly logger = new Logger(this.constructor.name);
public constructor(
@Inject(NATS_CLIENT) private readonly natsClient: ClientProxy,
) {}
......@@ -23,6 +25,10 @@ export class InvitationsService {
public createInvitation(
tenantId: string,
): Observable<EventDidcommConnectionsCreateInvitation['data']> {
this.logger.log({
message: 'Create an invitation',
labels: { tenantId },
});
return this.natsClient
.send<
EventDidcommConnectionsCreateInvitation,
......@@ -35,6 +41,11 @@ export class InvitationsService {
tenantId: string,
invitationUrl: string,
): Observable<EventDidcommConnectionsReceiveInvitationFromUrl['data']> {
this.logger.log({
message: 'Receive an invitation from URL',
labels: { tenantId },
'ocm.invitations.invitationUrl': invitationUrl,
});
return this.natsClient
.send<
EventDidcommConnectionsReceiveInvitationFromUrl,
......
......@@ -5,7 +5,7 @@ import type { IncomingMessage, ServerResponse } from 'http';
import { Logger, VersioningType } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { initOpenTelemetry } from '@ocm/shared';
import { createApplicationLogger, initOpenTelemetry } from '@ocm/shared';
import helmet from 'helmet';
import { createRequire } from 'module';
import { resolve } from 'node:path';
......@@ -19,7 +19,9 @@ const pkg = createRequire(import.meta.url)(pkgPath);
const { sdk, prometheusExporter } = initOpenTelemetry(pkg.name);
sdk.start();
const app = await NestFactory.create(Application);
const app = await NestFactory.create(Application, {
logger: createApplicationLogger(),
});
app.use('/metrics', (req: IncomingMessage, res: ServerResponse) => {
prometheusExporter.getMetricsRequestHandler(req, res);
......
......@@ -4,3 +4,7 @@ NATS_URL=nats://localhost:4222
NATS_USER=nats_user
NATS_PASSWORD=nats_password
NATS_MONITORING_URL=http://localhost:8222
POLICIES_URL=http://localhost:4100
POLICIES_AUTO_REVOCATION_POLICY=policies/xfsc/auto_revocation/1.0
POLICIES_AUTO_REISSUE_POLICY=policies/xfsc/auto_reissue/1.0
POLICIES_REFRESH_POLICY=policies/xfsc/refresh/1.0
This diff is collapsed.
# OCM Credential Manager
## Introduction
The OCM Credential Manager API enables you to:
- Fetch credentials, offers and requests
- Revoke credentials
- Accept credential offers
- Evaluate TSA policies for single credentials
## Prerequisites
Ensure you have Node.js installed ([official Node.js website](https://nodejs.org)).
## Configuration
Set configuration via environment variables or an `.env` file:
| Property | Description | Default |
|---|---|---|
| `HTTP_HOSTNAME` | HTTP server hostname | `0.0.0.0` |
| `HTTP_PORT` | HTTP server port | `3000` |
| `NATS_URL` | NATS Server URL | `nats://localhost:4222` |
| `NATS_USER` | NATS user | |
| `NATS_PASSWORD` | NATS password | |
| `NATS_MONITORING_URL` | NATS Monitoring URL | `http://localhost:8222` |
| `POLICIES_URL` | TSA Policy Manager URL | |
| `POLICIES_AUTO_REVOCATION_POLICY` | Policy name for auto revocation check | |
| `POLICIES_AUTO_REISSUE_POLICY` | Policy name for auto-reissue check | |
| `POLICIES_REFRESH_POLICY` | Policy name for refresh check | |
## Usage
Start in development mode:
```bash
pnpm start
```
### Operations
> **Note:** All requests need a `tenantId` query parameter.
#### Get credential list
```bash
curl -X GET http://ocm-indy.xfsc.dev/v1/credentials?tenantId=<tenantId>
```
Response:
```json
{
"status": 200,
"data": [...]
}
```
#### Revoke a credential
```bash
curl -X POST http://ocm-indy.xfsc.dev/v1/credentials/?tenantId=<tenantId>
```
Response:
```json
{
"status": 201,
"data": {}
}
```
## API Reference
For detailed documentation, refer to the [OpenAPI Specification](openapi.json).
## License
Licensed under the Apache 2.0 License ([LICENSE](LICENSE)).
This diff is collapsed.
......@@ -2,8 +2,9 @@
"name": "@ocm/credential-manager",
"version": "1.0.0",
"description": "Gaia-X OCM Credential Manager",
"author": "Konstantin Tsabolov <konstantin.tsabolov@spherity.com>",
"author": "Gaia-X",
"contributors": [
"Berend Sliedrecht <berend@animo.id>",
"Konstantin Tsabolov <konstantin.tsabolov@spherity.com>"
],
"private": true,
......