Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

consume latest verite lib and simplify / reuse CM/PDs #12

Merged
merged 1 commit into from
Sep 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 54 additions & 48 deletions lib/attestation-fns.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { faker } from "@faker-js/faker"
import { ethers } from "ethers"
import type { Attestation } from "verite"
import { ADDRESS_OWNER_ATTESTATION, Attestation, COUNTERPARTY_ACCOUNT_HOLDER_ATTESTATION, KYBPAML_ATTESTATION, KYCAML_ATTESTATION, KYCAML_CREDENTIAL_TYPE_NAME } from "verite"

import { AttestationKeys, AttestationTypes } from "./constants"
import { apiDebug } from "./debug"

type GenerateAttestationOptions = {
approvalDate?: Date
Expand All @@ -9,68 +12,71 @@ type GenerateAttestationOptions = {
}

type GenerateAttestation = (
type: string,
type: AttestationTypes,
opts?: GenerateAttestationOptions
) => Promise<Attestation>

/**
*
*/
export const generateAttestation: GenerateAttestation = async (type, opts) => {
if (type === "kycaml") {
const approvalDate = opts?.approvalDate || new Date()
const approvalDate = opts?.approvalDate || new Date()
apiDebug(`generateAttestation for type=${type}`)

if (type.definition.process) {
return {
type: "KYCAMLAttestation",
process: "https://verite.id/definitions/processes/kycaml/0.0.1/usa",
type: type.type,
process: type.definition.process,
approvalDate: approvalDate.toISOString()
}
}

if (type === "kybaml") {
const approvalDate = opts?.approvalDate || new Date()

return {
type: "KYBPAMLAttestation",
process:
"https://verite.id/definitions/processes/kycaml/0.0.1/generic--usa-legal_person",
approvalDate: approvalDate.toISOString()
} else {
if (type.id === AttestationKeys.address) {
if (!opts?.chain) {
throw new Error("Missing attribute: chain")
}
const wallet = ethers.Wallet.createRandom()
const issuanceDate = opts?.issuanceDate ?? new Date()
const proof = await wallet.signMessage(
[opts.chain, wallet.address, issuanceDate.toISOString()].join("")
)
return {
type: ADDRESS_OWNER_ATTESTATION,
chain: opts.chain,
address: wallet.address,
proof
}
}
}

if (type === "address") {
if (!opts?.chain) {
throw new Error("Missing attribute: chain")
}
const wallet = ethers.Wallet.createRandom()
const issuanceDate = opts?.issuanceDate ?? new Date()
const proof = await wallet.signMessage(
[opts.chain, wallet.address, issuanceDate.toISOString()].join("")
)

return {
type: "AddressOwner",
chain: opts.chain,
address: wallet.address,
proof
}
}

if (type === "counterparty") {
return {
type: "CounterpartyAccountHolder",
legalName: faker.name.findName(),
address: {
type: "PostalAddress",
addressLocality: faker.address.city(),
addressRegion: faker.address.stateAbbr(),
postalCode: faker.address.zipCode(),
addressCountry: "United States"
},
accountNumber: faker.finance.ethereumAddress()

if (type.id === AttestationKeys.counterparty) {
return {
type: COUNTERPARTY_ACCOUNT_HOLDER_ATTESTATION,
legalName: faker.name.findName(),
address: {
type: "PostalAddress",
addressLocality: faker.address.city(),
addressRegion: faker.address.stateAbbr(),
postalCode: faker.address.zipCode(),
addressCountry: "United States"
},
accountNumber: faker.finance.ethereumAddress()
}
}
}

// Unknown Attestation type, throw.
throw new Error(`Unknown attestation type: ${type}`)
}


export function getCredentialType(attestationType: string): string {
if (attestationType === KYCAML_ATTESTATION) {
return KYCAML_CREDENTIAL_TYPE_NAME
} else if (attestationType === KYBPAML_ATTESTATION) {
return "KYBPAMLCredential"
} else if (attestationType === ADDRESS_OWNER_ATTESTATION) {
return "AddressOwnerCredential"
} else if (attestationType === COUNTERPARTY_ACCOUNT_HOLDER_ATTESTATION) {
return "CounterpartyAccountHolderCredential"
}
throw new Error(`Unrecognized attestation type ${attestationType}`)
}
39 changes: 27 additions & 12 deletions lib/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ADDRESS_OWNER_ATTESTATION, AttestationDefinition, COUNTERPARTY_ACCOUNT_HOLDER_ATTESTATION, getAttestionDefinition, KYBPAML_ATTESTATION, KYCAML_ATTESTATION } from "verite"

/**
*
*/
Expand All @@ -7,13 +9,21 @@ export type BaseCredentialProperty<T = string> = {
secondary?: string
}

export enum AttestationKeys {
kycaml = "kycaml",
kybpaml = "kybpaml",
address = "addresss",
counterparty = "counterparty"
}

/**
*
*/
export type CredentialType = BaseCredentialProperty<
"kycaml" | "kybaml" | "address" | "counterparty"
export type AttestationTypes = BaseCredentialProperty<
AttestationKeys
> & {
type: string
type: string,
definition: AttestationDefinition
}

/**
Expand Down Expand Up @@ -58,26 +68,31 @@ export type ChainId = BaseCredentialProperty & {
/**
*
*/
export const CREDENTIAL_TYPES: CredentialType[] = [
export const ATTESTATION_TYPES: AttestationTypes[] = [
{
id: "kycaml",
id: AttestationKeys.kycaml,
name: "KYC/AML Attestation",
type: "KYCAMLAttestation"
type: KYCAML_ATTESTATION,
definition: getAttestionDefinition(KYCAML_ATTESTATION)
},
{
id: "kybaml",
id: AttestationKeys.kybpaml,
name: "KYBP/AML Attestation",
type: "KYBPAMLAttestation"
type: KYBPAML_ATTESTATION,
definition: getAttestionDefinition(KYBPAML_ATTESTATION)
},
{
id: "address",
id: AttestationKeys.address,
name: "Address Ownership",
type: "AddressOwner"
type: ADDRESS_OWNER_ATTESTATION,
definition: getAttestionDefinition(ADDRESS_OWNER_ATTESTATION)

},
{
id: "counterparty",
id: AttestationKeys.counterparty,
name: "Counterparty Compliance",
type: "CounterpartyAccountHolder"
type: COUNTERPARTY_ACCOUNT_HOLDER_ATTESTATION,
definition: getAttestionDefinition(COUNTERPARTY_ACCOUNT_HOLDER_ATTESTATION)
}
]

Expand Down
10 changes: 5 additions & 5 deletions lib/credential-fns.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
CredentialType,
CREDENTIAL_TYPES,
AttestationTypes,
ATTESTATION_TYPES,
CredentialIssuer,
CREDENTIAL_ISSUERS,
CredentialStatus,
Expand All @@ -18,10 +18,10 @@ const TWO_MONTHS = 2 * 30 * 24 * 60 * 60 * 1000
/**
*
*/
export const findCredentialType = (id: string): CredentialType => {
const item = CREDENTIAL_TYPES.find((t) => t.id === id)
export const findAttestationType = (id: string): AttestationTypes => {
const item = ATTESTATION_TYPES.find((t) => t.id === id)
if (!item) {
throw new Error(`Unknown credential type: ${id}`)
throw new Error(`Unknown attestation type: ${id}`)
}
return item
}
Expand Down
63 changes: 16 additions & 47 deletions lib/manifest-fns.ts
Original file line number Diff line number Diff line change
@@ -1,60 +1,29 @@
import type { CredentialManifest, PresentationDefinition } from "verite"
import { CredentialManifest, CredentialManifestBuilder, CREDENTIAL_MANIFEST_SPEC_VERSION_1_0_0, PresentationDefinition, proofOfControlPresentationDefinition } from "verite"

import { fullURL } from "./url-fns"
import { apiDebug } from "./debug"

import { CredentialIssuer, CredentialType } from "lib/constants"
import { findCredentialType } from "lib/credential-fns"
import { OUTPUT_DESCRIPTORS } from "lib/manifest/output-descriptors"
import { CredentialIssuer, AttestationTypes } from "lib/constants"
import { getOutputDescriptors } from "lib/manifest/output-descriptors"

const PRESENTATION_DEFINITION: PresentationDefinition = {
id: "PROOF_OF_CONTROL_PRESENTATION_DEF_ID",
format: {
jwt_vp: {
alg: ["EdDSA"]
}
},
input_descriptors: [
{
id: "proofOfIdentifierControlVP",
name: "Proof of Control Verifiable Presentation",
purpose:
"A Verifiable Presentation establishing proof of identifier control over the DID.",
schema: [
{
uri: fullURL("/api/schemas/ProofOfControl")
}
]
}
]
}

const PRESENTATION_DEFINITION: PresentationDefinition = proofOfControlPresentationDefinition()

export type GenerateManifest = (
type: CredentialType["id"],
type: AttestationTypes,
issuer: CredentialIssuer
) => CredentialManifest

/**
*
*/
export const generateManifest: GenerateManifest = (type, issuer) => {
const credentialType = findCredentialType(type)

return {
id: credentialType.type,
version: "0.1.0",
issuer: {
id: issuer.did.key,
name: issuer.name
},
format: {
jwt_vc: {
alg: ["EdDSA"]
},
jwt_vp: {
alg: ["EdDSA"]
}
},
output_descriptors: [OUTPUT_DESCRIPTORS[type]],
presentation_definition: PRESENTATION_DEFINITION
}
apiDebug(`generateManifest => getAttestationInformation(${JSON.stringify(type)})`)
const outputDescriptors = getOutputDescriptors(issuer.name, type)
return new CredentialManifestBuilder(type.type).issuer( {
id: issuer.did.key,
name: issuer.name
})
.output_descriptors(outputDescriptors)
.presentation_definition(PRESENTATION_DEFINITION)
.build()
}
70 changes: 32 additions & 38 deletions lib/manifest/output-descriptors/address.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,35 @@
import { fullURL } from "lib/url-fns"
import { LabeledDisplayMappingBuilder, OutputDescriptor, STRING_SCHEMA } from "verite"

export const descriptor = {
id: "address-output-descriptor",
schema: [
import { AttestationTypes } from "lib/constants"

export function getOutputDescriptors(issuerName: string, type: AttestationTypes): OutputDescriptor[] {

const properties = [
new LabeledDisplayMappingBuilder("Chain", STRING_SCHEMA).path([`$.${type.type}.chain`]).build(),
new LabeledDisplayMappingBuilder("Address", STRING_SCHEMA).path([`$.${type.type}.address`]).build(),
new LabeledDisplayMappingBuilder("Proof", STRING_SCHEMA).path([`$.${type.type}.proof`]).build(),
]
const outputs = [
{
uri: fullURL("/api/schemas/AddressOwner")
}
],
name: "Proof of Address Ownership",
description: "Attestation that the subject owns a given address",
display: {
title: {
text: "Address Ownership"
},
subtitle: {
path: ["$.AddressOwner.address"],
fallback: "Includes address"
},
description: {
text: "Expresses proof of ownership of an address for any chain that uses public-private key cryptography in address ownership."
},
properties: [
{
label: "Chain",
path: ["$.AddressOwner.chain"],
schema: { type: "string" }
},
{
label: "Address",
path: ["$.AddressOwner.address"],
schema: { type: "string" }
},
{
label: "Proof",
path: ["$.AddressOwner.proof"],
schema: { type: "string" }
id: `${type.type}`,
schema: type.definition.schema,
name: "Proof of Address Ownership",
description: "Attestation that the subject owns a given address",
display: {
title: {
text: "Address Ownership"
},
subtitle: {
path: [`$.${type.type}.address`],
fallback: "Includes address"
},
description: {
text: "Expresses proof of ownership of an address for any chain that uses public-private key cryptography in address ownership."
},
properties: properties
}
]
}
}
}
]
return outputs

}
Loading