From c2b8efc972e404a63d79dee42e767af7d95ca0b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9cio=20Varj=C3=A3o?= <1348549+cvarjao@users.noreply.github.com> Date: Thu, 31 Oct 2024 14:40:17 -0700 Subject: [PATCH] add deep link test case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Clécio Varjão <1348549+cvarjao@users.noreply.github.com> --- src/AgentManual.ts | 4 +- src/deep-links.test.ts | 96 ++++++++++++++++++++++++++++++++++++++++++ src/lib.ts | 18 ++++++-- 3 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 src/deep-links.test.ts diff --git a/src/AgentManual.ts b/src/AgentManual.ts index ae96252..c9ea4a0 100644 --- a/src/AgentManual.ts +++ b/src/AgentManual.ts @@ -50,8 +50,8 @@ export class AgentManual implements AriesAgent { const relativePath = './tmp/__qrcode.png' const QRCodePath = path.resolve(process.cwd() as string, relativePath) fs.mkdirSync(path.dirname(QRCodePath), { recursive: true }) - fs.writeFileSync(path.join(process.cwd(), 'invitation_url.txt'), ref.payload.invitation_url) - fs.writeFileSync(path.join(process.cwd(), 'invitation.json'), JSON.stringify((ref.payload.invitation as any))) + //fs.writeFileSync(path.join(process.cwd(), 'invitation_url.txt'), ref.payload.invitation_url) + //fs.writeFileSync(path.join(process.cwd(), 'invitation.json'), JSON.stringify((ref.payload.invitation as any))) await QRCode.toFile( QRCodePath, ref.payload.invitation_url, diff --git a/src/deep-links.test.ts b/src/deep-links.test.ts new file mode 100644 index 0000000..1e55b3c --- /dev/null +++ b/src/deep-links.test.ts @@ -0,0 +1,96 @@ +import { describe, test } from "@jest/globals"; +import { AgentTraction } from "./AgentTraction"; +import { AgentCredo } from "./AgentCredo"; +import { LogLevel } from "@credo-ts/core"; +import { PersonSchemaV1_1 } from "./mocks"; +import { CredentialDefinitionBuilder, PinoLogger, withDeepLinkPage, withRedirectUrl } from "./lib"; +import pino from "pino"; + +const stepTimeout = 120_000 +const shortTimeout = 40_000 +import { dir as console_dir } from "console" +import { setGlobalDispatcher, Agent} from 'undici'; +import { AriesAgent, INVITATION_TYPE } from "./Agent"; +import { AgentManual } from "./AgentManual"; +import { cache_requests } from "./axios-traction-serializer"; +setGlobalDispatcher(new Agent({connect: { timeout: 20_000 }})); + +export const loggerTransport = pino.transport({ + targets: [ + { + level: 'trace', + target: 'pino/file', + options: { + destination: `./logs/run-${Date.now()}.log.ndjson`, + autoEnd: true, + }, + } + ], +}) + +describe("deep-links", () => { + const _logger = pino({ level: 'trace', timestamp: pino.stdTimeFunctions.isoTime, }, loggerTransport); + const logger = new PinoLogger(_logger, LogLevel.trace) + // eslint-disable-next-line @typescript-eslint/no-var-requires + const config = require("../local.env.json") + // eslint-disable-next-line @typescript-eslint/no-var-requires + const ledgers = require("../ledgers.json"); + const agentSchemaOwner = new AgentTraction(config.schema_owner, logger); + const agentIssuer = new AgentTraction(config.issuer, logger); + const agentVerifier = new AgentTraction(config.verifier, logger); + //const agentB: AriesAgent = new AgentManual(config, new ConsoleLogger(LogLevel.trace)) + const agentB: AriesAgent = process.env.HOLDER_TYPE === 'manual'? new AgentManual(config.holder, logger): new AgentCredo(config.holder,ledgers, logger) + //new PinoLogger(logger, LogLevel.trace)); + const schema = new PersonSchemaV1_1(); + const credDef = new CredentialDefinitionBuilder() + .setSchema(schema) + .setSupportRevocation(true) + .setTag('Revocable Credential') + const requests: unknown[] = [] + beforeAll(async () => { + logger.info('1 - beforeAll') + await agentSchemaOwner.startup() + await agentIssuer.startup() + await agentB.startup() + await agentVerifier.startup() + //await Promise.all([agentA.startup(), agentB.startup()]); + agentSchemaOwner.axios.interceptors.request.use(cache_requests(requests)) + agentIssuer.axios.interceptors.request.use(cache_requests(requests)) + agentVerifier.axios.interceptors.request.use(cache_requests(requests)) + agentIssuer.axios.interceptors.response.use( async (response) => { + return response + }, (error) => { + console_dir(error.response) + return Promise.reject(error); + }) + + await agentSchemaOwner.createSchema(schema); + await agentIssuer.createSchemaCredDefinition(credDef); + }, stepTimeout); + afterAll(async () => { + logger.info('1 - afterAll') + await agentB.shutdown(); + _logger.flush(); + //loggerTransport.end(); + }, stepTimeout); + beforeEach(async () => { + requests.length = 0 + }) + test("OOB/connected/messaging", async () => { + const issuer = agentIssuer + const holder = agentB + logger.info(`Executing ${expect.getState().currentTestName}`) + const remoteInvitation = await withDeepLinkPage(await withRedirectUrl(await issuer.createInvitationToConnect(INVITATION_TYPE.OOB_DIDX_1_1))) + logger.info(`waiting for holder to accept connection`) + const agentBConnectionRef1 = await holder.receiveInvitation(remoteInvitation) + logger.info(`waiting for issuer to accept connection`) + const {connection_id} = await issuer.waitForOOBConnectionReady(remoteInvitation.payload.invi_msg_id) + logger.info(`${connection_id} connected to ${agentBConnectionRef1.connectionRecord?.connection_id}`) + logger.info('agentBConnectionRef1', agentBConnectionRef1) + const msgSent: any = await issuer.sendBasicMessage(connection_id, 'Hello') + logger.info('Message Sent:', msgSent) + await holder.sendBasicMessage(agentBConnectionRef1.connectionRecord?.connection_id as string, 'ok') + const msgRcvd = await issuer.waitForBasicMessage(connection_id, Date.parse(msgSent.created_at as string), ["k", "ok"]) + logger.info('Message Received:', msgRcvd) + }, stepTimeout); +}); diff --git a/src/lib.ts b/src/lib.ts index 3f522ae..e31c44b 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -1,9 +1,9 @@ import axios, {AxiosInstance} from 'axios'; import { PersonCredential1 } from './mocks'; -import { BaseLogger, InvitationType, LogLevel, ProofExchangeRecord } from '@credo-ts/core'; +import { BaseLogger, LogLevel, ProofExchangeRecord } from '@credo-ts/core'; import { Logger } from 'pino'; import { AgentTraction } from './AgentTraction'; -import { AriesAgent, INVITATION_TYPE, ResponseCreateInvitation, ResponseCreateInvitationV1, ResponseCreateInvitationV2 } from './Agent'; +import { AriesAgent, CreateInvitationResponse, INVITATION_TYPE, ResponseCreateInvitationV1, ResponseCreateInvitationV2 } from './Agent'; import fs from 'node:fs'; import path from 'node:path'; import { log, dir} from "console" @@ -921,7 +921,19 @@ export const verifyCredentialA2 = async (verifier:AriesAgent, holder: AriesAgent logger.info('Verifier is waiting for proofs') await verifier.waitForPresentation(remoteInvitation3.payload.presentation_exchange_id as string) } - export const withRedirectUrl = async (remoteInvitation3: ResponseCreateInvitation): Promise => { + export function base64URLencode(str: string) { + const base64Encoded = encodeURIComponent(str) + return base64Encoded.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); + } + export const withDeepLinkPage = async (remoteInvitation3: CreateInvitationResponse): Promise> => { + const invitationFile = `${remoteInvitation3.payload.invitation['@id']}.html` + fs.writeFileSync(path.join(process.cwd(), `/tmp/${invitationFile}`), `

click here

`) + const publicUrl = await axios.get('http://127.0.0.1:4040/api/tunnels').then((response)=>{return response.data.tunnels[0].public_url as string}) + remoteInvitation3.payload.invitation_url = `${publicUrl}/${invitationFile}` + + return remoteInvitation3 + } + export const withRedirectUrl = async (remoteInvitation3: CreateInvitationResponse): Promise> => { const invitationFile = `${remoteInvitation3.payload.invitation['@id']}.json` fs.writeFileSync(path.join(process.cwd(), `/tmp/${invitationFile}`), JSON.stringify(remoteInvitation3.payload.invitation, undefined, 2)) const publicUrl = await axios.get('http://127.0.0.1:4040/api/tunnels').then((response)=>{return response.data.tunnels[0].public_url as string})