Skip to content

Commit

Permalink
feat: credential revocation management in nestjs-client (#64)
Browse files Browse the repository at this point in the history
  • Loading branch information
lotharking authored Jan 22, 2025
1 parent 96f2aac commit 9758805
Show file tree
Hide file tree
Showing 33 changed files with 777 additions and 118 deletions.
2 changes: 2 additions & 0 deletions examples/demo-dts/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ services:
- AGENT_WALLET_KEY_DERIVATION_METHOD=ARGON2I_INT
- AGENT_INVITATION_BASE_URL=https://hologram.zone/
- REDIS_HOST=redis
volumes:
- ./afj:/root/.afj

chatbot-dts:
build:
Expand Down
25 changes: 13 additions & 12 deletions examples/demo-dts/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ConfigModule } from '@nestjs/config'
import appConfig from '@/config/app.config'
import { AcceptLanguageResolver, HeaderResolver, I18nModule, QueryResolver } from 'nestjs-i18n'
import * as path from 'path'
import { ConnectionsEventModule, MessageEventModule } from '@2060.io/service-agent-nestjs-client'
import { EventsModule } from '@2060.io/service-agent-nestjs-client'
import { ApiVersion } from '@2060.io/service-agent-client'
import { CoreModule } from '@/core.module'

Expand All @@ -27,18 +27,19 @@ import { CoreModule } from '@/core.module'
isGlobal: true,
load: [appConfig],
}),
MessageEventModule.forRoot({
eventHandler: CoreService,
imports: [],
url: process.env.SERVICE_AGENT_ADMIN_URL,
version: ApiVersion.V1,
}),
ConnectionsEventModule.forRoot({
eventHandler: CoreService,
imports: [],
EventsModule.register({
modules: {
messages: true,
connections: true,
credentials: true,
},
options: {
eventHandler: CoreService,
imports: [],
url: process.env.SERVICE_AGENT_ADMIN_URL,
version: ApiVersion.V1,
},
}),
],
controllers: [],
providers: [CoreService],
})
export class AppModule {}
4 changes: 4 additions & 0 deletions examples/demo-dts/src/common/enums/cmd.enum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum Cmd {
CREDENTIAL = '/credential',
REVOKE = '/revoke',
}
1 change: 1 addition & 0 deletions examples/demo-dts/src/common/enums/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './cmd.enum'
export * from './menu-select.enum'
export * from './state-step.enum'
1 change: 0 additions & 1 deletion examples/demo-dts/src/config/app.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { ApiVersion } from '@2060.io/service-agent-client'
import { registerAs } from '@nestjs/config'

/**
Expand Down
6 changes: 3 additions & 3 deletions examples/demo-dts/src/core.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { Global, Module } from '@nestjs/common'
import { SessionEntity } from '@/models'
import { CoreService } from '@/core.service'
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm'
import { ConnectionEntity } from '@2060.io/service-agent-nestjs-client'
import { ConnectionEntity, CredentialEntity, RevocationRegistryEntity } from '@2060.io/service-agent-nestjs-client'
import { ConfigModule, ConfigService } from '@nestjs/config'

@Global()
@Module({
imports: [
TypeOrmModule.forFeature([ConnectionEntity, SessionEntity]),
TypeOrmModule.forFeature([ConnectionEntity, CredentialEntity, RevocationRegistryEntity, SessionEntity]),
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService): Promise<TypeOrmModuleOptions> => ({
Expand All @@ -18,7 +18,7 @@ import { ConfigModule, ConfigService } from '@nestjs/config'
username: configService.get<string>('appConfig.postgresUser'),
password: configService.get<string>('appConfig.postgresPassword'),
database: configService.get<string>('appConfig.postgresDbName'),
entities: [ConnectionEntity, SessionEntity],
entities: [ConnectionEntity, CredentialEntity, RevocationRegistryEntity, SessionEntity],
synchronize: true,
ssl: false,
logging: false,
Expand Down
91 changes: 81 additions & 10 deletions examples/demo-dts/src/core.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import {
BaseMessage,
Claim,
ConnectionStateUpdated,
ContextualMenuItem,
ContextualMenuSelectMessage,
ContextualMenuUpdateMessage,
CredentialReceptionMessage,
EMrtdDataSubmitMessage,
MediaMessage,
Expand All @@ -11,18 +14,18 @@ import {
TextMessage,
} from '@2060.io/service-agent-model'
import { ApiClient, ApiVersion } from '@2060.io/service-agent-client'
import { EventHandler } from '@2060.io/service-agent-nestjs-client'
import { Injectable, Logger } from '@nestjs/common'
import { CredentialService, EventHandler } from '@2060.io/service-agent-nestjs-client'
import { Injectable, Logger, OnModuleInit } from '@nestjs/common'
import { SessionEntity } from './models'
import { JsonTransformer } from '@credo-ts/core'
import { StateStep } from './common'
import { Cmd, StateStep } from './common'
import { Repository } from 'typeorm'
import { InjectRepository } from '@nestjs/typeorm'
import { I18nService } from 'nestjs-i18n'
import { ConfigService } from '@nestjs/config'

@Injectable()
export class CoreService implements EventHandler {
export class CoreService implements EventHandler, OnModuleInit {
private readonly apiClient: ApiClient
private readonly logger = new Logger(CoreService.name)

Expand All @@ -31,11 +34,22 @@ export class CoreService implements EventHandler {
private readonly sessionRepository: Repository<SessionEntity>,
private readonly i18n: I18nService,
private readonly configService: ConfigService,
private readonly credentialService: CredentialService,
) {
const baseUrl = configService.get<string>('appConfig.serviceAgentAdminUrl')
this.apiClient = new ApiClient(baseUrl, ApiVersion.V1)
}

async onModuleInit() {
await this.credentialService.createType(
'demo dts',
'1.0',
['fullName', 'issuanceDate'], {
supportRevocation: true,
maximumCredentialNumber: 5,
})
}

/**
* Handles incoming messages and manages the input flow.
* Routes the message to the appropriate handler based on its type.
Expand Down Expand Up @@ -102,7 +116,8 @@ export class CoreService implements EventHandler {
* @param event - The event containing connection update details.
*/
async newConnection(event: ConnectionStateUpdated): Promise<void> {
await this.handleSession(event.connectionId)
const session = await this.handleSession(event.connectionId)
await this.sendContextualMenu(session)
}

/**
Expand All @@ -128,8 +143,8 @@ export class CoreService implements EventHandler {
* metadata remain intact while cleaning up unnecessary or sensitive data.
*/
async closeConnection(event: ConnectionStateUpdated): Promise<void> {
let session = await this.handleSession(event.connectionId)
session = await this.purgeUserData(session)
const session = await this.handleSession(event.connectionId)
await this.purgeUserData(session)
}

private async welcomeMessage(connectionId: string) {
Expand Down Expand Up @@ -170,8 +185,27 @@ export class CoreService implements EventHandler {
* @param selectionId - Identifier of the user's selection.
* @param session - The current session associated with the message.
*/
private handleContextualAction(selectionId: string, session: SessionEntity): Promise<SessionEntity> {
throw new Error('Function not implemented.')
private async handleContextualAction(selectionId: string, session: SessionEntity): Promise<SessionEntity> {
switch (session.state) {
case StateStep.START:
if (selectionId === Cmd.CREDENTIAL) {
const claims = [
new Claim({ name: 'fullName', value: 'example' }),
new Claim({ name: 'issuanceDate', value: new Date().toISOString().split('T')[0] }),
]
await this.credentialService.issue(session.connectionId, claims, {
refId: claims[0].value,
revokeIfAlreadyIssued: true,
})
}
if (selectionId === Cmd.REVOKE) {
await this.credentialService.revoke(session.connectionId)
}
break
default:
break
}
return await this.sessionRepository.save(session)
}

/**
Expand All @@ -182,7 +216,11 @@ export class CoreService implements EventHandler {
* @param session - The active session to update.
*/
private async handleStateInput(content: any, session: SessionEntity): Promise<SessionEntity> {
throw new Error('Function not implemented.')
try {
} catch (error) {
this.logger.error('handleStateInput: ' + error)
}
return await this.sendContextualMenu(session)
}

/**
Expand Down Expand Up @@ -246,4 +284,37 @@ export class CoreService implements EventHandler {
// Additional sensitive data can be reset here if needed.
return await this.sessionRepository.save(session)
}

// send special flows
private async sendContextualMenu(session: SessionEntity): Promise<SessionEntity> {
const item: ContextualMenuItem[] = []
switch (session.state) {
case StateStep.START:
item.push(
new ContextualMenuItem({
id: Cmd.CREDENTIAL,
title: this.getText('CMD.CREDENTIAL', session.lang),
}),
)
item.push(
new ContextualMenuItem({
id: Cmd.REVOKE,
title: this.getText('CMD.REVOKE', session.lang),
}),
)
break
default:
break
}

await this.apiClient.messages.send(
new ContextualMenuUpdateMessage({
title: this.getText('ROOT_TITLE', session.lang),
connectionId: session.connectionId,
options: item,
timestamp: new Date(),
}),
)
return await this.sessionRepository.save(session)
}
}
5 changes: 5 additions & 0 deletions examples/demo-dts/src/i18n/en/msg.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"WELCOME":"Welcome to our demo chatbot",
"ROOT_TITLE": "Context Menu",
"CMD": {
"CREDENTIAL":"New credential",
"REVOKE":"Revoke credential"
},
"HELP":"Check the contextual menu for available actions."
}
5 changes: 5 additions & 0 deletions examples/demo-dts/src/i18n/es/msg.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"WELCOME":"Bienvenido a nuestro chatbot Demo",
"ROOT_TITLE": "Menú Contextual",
"CMD": {
"CREDENTIAL":"Nueva credencial",
"REVOKE":"Revocar credencial"
},
"HELP":"Acceder al menu contextual para ver las opciones disponibles."
}
54 changes: 44 additions & 10 deletions examples/demo-dts/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
# yarn lockfile v1


"@2060.io/service-agent-model@file:../../packages/model/build":
"@2060.io/service-agent-client@file:../../packages/client/build":
version "0.0.0"

"@2060.io/service-agent-nestjs-client@file:../../packages/nestjs-client/build":
"@2060.io/service-agent-model@file:../../packages/model/build":
version "0.0.0"

"@2060.io/service-agent-client@file:../../packages/client/build":
"@2060.io/service-agent-nestjs-client@file:../../packages/nestjs-client/build":
version "0.0.0"

"@ampproject/remapping@^2.2.0":
Expand Down Expand Up @@ -934,6 +934,11 @@
resolved "https://registry.yarnpkg.com/@lukeed/csprng/-/csprng-1.1.0.tgz#1e3e4bd05c1cc7a0b2ddbd8a03f39f6e4b5e6cfe"
integrity sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==

"@microsoft/tsdoc@^0.15.0":
version "0.15.1"
resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.15.1.tgz#d4f6937353bc4568292654efb0a0e0532adbcba2"
integrity sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==

"@multiformats/base-x@^4.0.1":
version "4.0.1"
resolved "https://registry.yarnpkg.com/@multiformats/base-x/-/base-x-4.0.1.tgz#95ff0fa58711789d53aefb2590a8b7a4e715d121"
Expand Down Expand Up @@ -999,6 +1004,11 @@
path-to-regexp "3.3.0"
tslib "2.7.0"

"@nestjs/mapped-types@2.0.6":
version "2.0.6"
resolved "https://registry.yarnpkg.com/@nestjs/mapped-types/-/mapped-types-2.0.6.tgz#d2d8523709fd5d872a9b9e0c38162746e2a7f44e"
integrity sha512-84ze+CPfp1OWdpRi1/lOu59hOhTz38eVzJvRKrg9ykRFwDz+XleKfMsG0gUqNZYFa6v53XYzeD+xItt8uDW7NQ==

"@nestjs/platform-express@^10.0.0":
version "10.4.6"
resolved "https://registry.yarnpkg.com/@nestjs/platform-express/-/platform-express-10.4.6.tgz#6c39c522fa66036b4256714fea203fbeb49fc4de"
Expand All @@ -1021,6 +1031,18 @@
jsonc-parser "3.3.1"
pluralize "8.0.0"

"@nestjs/swagger@^8.0.7":
version "8.1.0"
resolved "https://registry.yarnpkg.com/@nestjs/swagger/-/swagger-8.1.0.tgz#e55434053df454b5058ead94e33d94dcf4525e8f"
integrity sha512-8hzH+r/31XshzXHC9vww4T0xjDAxMzvOaT1xAOvvY1LtXTWyNRCUP2iQsCYJOnnMrR+vydWjvRZiuB3hdvaHxA==
dependencies:
"@microsoft/tsdoc" "^0.15.0"
"@nestjs/mapped-types" "2.0.6"
js-yaml "4.1.0"
lodash "4.17.21"
path-to-regexp "3.3.0"
swagger-ui-dist "5.18.2"

"@nestjs/testing@^10.0.0":
version "10.4.6"
resolved "https://registry.yarnpkg.com/@nestjs/testing/-/testing-10.4.6.tgz#3797a40c0628788e381f299d3c72acac364ca4ef"
Expand Down Expand Up @@ -1244,6 +1266,11 @@
"@protokoll/core" "0.2.36"
compare-versions "^6.1.1"

"@scarf/scarf@=1.4.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@scarf/scarf/-/scarf-1.4.0.tgz#3bbb984085dbd6d982494538b523be1ce6562972"
integrity sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==

"@sd-jwt/core@0.7.2", "@sd-jwt/core@^0.7.0":
version "0.7.2"
resolved "https://registry.yarnpkg.com/@sd-jwt/core/-/core-0.7.2.tgz#cfbcd853d507e2c31bf66ea5b2c1748291924ec3"
Expand Down Expand Up @@ -4331,6 +4358,13 @@ js-base64@^3.7.6:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==

js-yaml@4.1.0, js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
dependencies:
argparse "^2.0.1"

js-yaml@^3.13.1:
version "3.14.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537"
Expand All @@ -4339,13 +4373,6 @@ js-yaml@^3.13.1:
argparse "^1.0.7"
esprima "^4.0.0"

js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
dependencies:
argparse "^2.0.1"

jsesc@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e"
Expand Down Expand Up @@ -5825,6 +5852,13 @@ supports-preserve-symlinks-flag@^1.0.0:
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==

swagger-ui-dist@5.18.2:
version "5.18.2"
resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-5.18.2.tgz#62013074374d272c04ed3030704b88db5aa8c0b7"
integrity sha512-J+y4mCw/zXh1FOj5wGJvnAajq6XgHOyywsa9yITmwxIlJbMqITq3gYRZHaeqLVH/eV/HOPphE6NjF+nbSNC5Zw==
dependencies:
"@scarf/scarf" "=1.4.0"

symbol-observable@4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205"
Expand Down
Loading

0 comments on commit 9758805

Please sign in to comment.