Skip to content
Snippets Groups Projects
agent.utils.ts 6.5 KiB
Newer Older
import {
  Agent,
  AutoAcceptCredential,
  AutoAcceptProof,
  ConnectionsModule,
  CredentialsModule,
  DidsModule,
  Key,
  KeyType,
  ProofsModule,
  TypedArrayEncoder,
  V2CredentialProtocol,
  V2ProofProtocol,
  WalletError,
  WalletKeyExistsError,
} from "@aries-framework/core";
import {
  AnonCredsCredentialFormatService,
  AnonCredsModule,
  AnonCredsProofFormatService,
} from "@aries-framework/anoncreds";
import {
  IndyVdrAnonCredsRegistry,
  IndyVdrIndyDidRegistrar,
  IndyVdrIndyDidResolver,
  IndyVdrModule,
} from "@aries-framework/indy-vdr";
import { AnonCredsRsModule } from "@aries-framework/anoncreds-rs";
import { anoncreds } from "@hyperledger/anoncreds-nodejs";
import { indyVdr } from "@hyperledger/indy-vdr-nodejs";
import { AskarModule } from "@aries-framework/askar";
import { ariesAskar } from "@hyperledger/aries-askar-nodejs";
import { Key as C, KeyAlgs } from "@hyperledger/aries-askar-shared";
import { IConfAgent } from "@ocm-engine/config";
import axios from "axios";

export const importDidsToWallet = async (
  agent: Agent,
  dids: Array<string>,
): Promise<void> => {
  for (const did in dids) {
    try {
      await agent.dids.import({
        did: dids[did],
        overwrite: false,
      });
    } catch (e) {
      console.log((e as Error).message);
    }
  }
};

export const generateKey = async ({
  seed,
  agent,
}: {
  seed: string;
  agent: Agent;
}): Promise<Key> => {
  if (!seed) {
    throw Error("No seed provided");
  }

  const privateKey = TypedArrayEncoder.fromString(seed);

  try {
    return await agent.wallet.createKey({
      seed: privateKey,
      keyType: KeyType.Ed25519,
    });
  } catch (e) {
    if (e instanceof WalletKeyExistsError) {
      const c = C.fromSecretBytes({
        algorithm: KeyAlgs.Ed25519,
        secretKey: TypedArrayEncoder.fromString(seed),
      });

      return Key.fromPublicKey(c.publicBytes, KeyType.Ed25519);
    }

    if (e instanceof WalletError) {
      throw new Error(`Failed to create key - ${e.message}`);
    }

    throw new Error("Unknown");
};

export const generateDidFromKey = (key: Key): string => {
  if (!key) {
    throw new Error("Key not provided");
  }

  return TypedArrayEncoder.toBase58(key.publicKey.slice(0, 16));
};

//eslint-disable-next-line
export const getAskarAnonCredsIndyModules = (networks: any) => {
  return {
    connections: new ConnectionsModule({
      autoAcceptConnections: true,
    }),
    credentials: new CredentialsModule({
      autoAcceptCredentials: AutoAcceptCredential.ContentApproved,
      credentialProtocols: [
        new V2CredentialProtocol({
          credentialFormats: [new AnonCredsCredentialFormatService()],
        }),
      ],
    }),
    proofs: new ProofsModule({
      autoAcceptProofs: AutoAcceptProof.ContentApproved,
      proofProtocols: [
        new V2ProofProtocol({
          proofFormats: [new AnonCredsProofFormatService()],
        }),
      ],
    }),
    anoncreds: new AnonCredsModule({
      registries: [new IndyVdrAnonCredsRegistry()],
    }),
    anoncredsRs: new AnonCredsRsModule({
      anoncreds,
    }),
    indyVdr: new IndyVdrModule({
      indyVdr,
      networks,
    }),
    dids: new DidsModule({
      registrars: [new IndyVdrIndyDidRegistrar()],
      resolvers: [
        new IndyVdrIndyDidResolver(),
        new KeyDidResolver(),
        new PeerDidResolver(),
      ],
    }),
    askar: new AskarModule({
      ariesAskar,
    }),
  } as const;
};

export const svdxProofStateChangeHandler = async (
  ev: ProofStateChangedEvent,
  agent: Agent,
  config?: IConfAgent,
) => {
  if (ProofState.Done !== ev.payload.proofRecord.state) {
    return;
  }

  const presentationMessage = await agent.proofs.findPresentationMessage(
    ev.payload.proofRecord.id,
  );

  console.log(JSON.stringify(presentationMessage, null, 2));
  if (!presentationMessage) {
    console.log("No presentation message found");
    return;
  }

  const attachmentId = presentationMessage.formats[0].attachmentId;

  const attachment =
    presentationMessage.getPresentationAttachmentById(attachmentId);

  console.log(JSON.stringify(attachment, null, 2));
  if (!attachment) {
    console.log("No attachment found");
    return;
  }

  const email =
    attachment.getDataAsJson<AnonCredsProof>()?.requested_proof.revealed_attrs[
      "email"
    ].raw;

  if (!config?.agentSVDXWebHook) {
    console.log("Agent SVDX web hook not set");
    return;
  }

  try {
    await axios.post(
      config?.agentSVDXWebHook,
      {
        email,
        connectionId: ev.payload.proofRecord.connectionId,
      },
      {
        auth: {
          username: config?.agentSVDXBasicUser,
          password: config?.agentSVDXBasicPass,
        },
      },
    );
  } catch (e) {
    console.log(JSON.stringify(e, null, 2));
  }
};

export const svdxConnectionStateChangeHandler = async (
  ev: ConnectionStateChangedEvent,
  agent: Agent,
  config?: IConfAgent,
) => {
  if (
    ev.payload.connectionRecord.role === DidExchangeRole.Responder &&
    ev.payload.connectionRecord.state !== "completed"
  ) {
    return;
  }

  await agent.connections.addConnectionType(
    ev.payload.connectionRecord.id,
    ev.payload.connectionRecord.theirLabel || "svdx",
  );

  console.log("connection accepted", JSON.stringify(ev, null, 2));

  const connections = await agent.connections.findAllByConnectionTypes([
    ev.payload.connectionRecord.theirLabel || "svdx",
  ]);

  if (connections.length < 2) {
    return;
  }

  connections.sort(
    (a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(),
  );

  while (connections.length > 1) {
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    const con = connections.pop()!;

    console.log(`deleting ${con.id}`);
    await agent.connections.deleteById(con.id);
  }

  try {
    await agent.proofs.requestProof({
      protocolVersion: "v2",
      connectionId: connections[0].id,
      proofFormats: {
        anoncreds: {
          name: "proof-request",
          version: "1.0",
          requested_attributes: {
            email: {
              name: "email",
              restrictions: [
                {
                  schema_id: config?.agentSVDXSchemaId,
                  cred_def_id: config?.agentSVDXCredDefId,
                },
              ],
            },
          },
        },
      },
    });
  } catch (e) {
    console.log(JSON.stringify(e, null, 2));
    console.log("failed to issue credential");
  }
};