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

feat(coordinate-mediation): upgrade from 2.0 to 3.0 #1282

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
6d5f3ff
feat: coordinate mediation changes
radleylewis Oct 9, 2023
6162631
fix: typo on return
radleylewis Oct 25, 2023
9a788de
fix: incl. beta flags, remove unnecessarily introduced body property …
radleylewis Oct 25, 2023
18a9a3d
chore: address merge conflicts
radleylewis Nov 10, 2023
74364a6
patch: apply didcomm changes patch
radleylewis Oct 25, 2023
6facf7a
refactor: pass DIDComm config from agent.yml as object
radleylewis Oct 25, 2023
5414c0d
refactor: use dataStoreIsMediationGranted for routing-message-handler…
radleylewis Oct 25, 2023
cd3dae5
docs: add documentation comments for dataStoreGetMediationPolicies
radleylewis Oct 25, 2023
0f817af
docs: build out documentation in coordinate-mediation-message-handler.ts
radleylewis Oct 25, 2023
7d2bb1c
docs: update documentation on newly introduces data-store entities
radleylewis Oct 25, 2023
d94bd61
fix: add @beta tag on IMediation type dec
radleylewis Oct 26, 2023
66d2b4a
build: generate updated plugin schema
radleylewis Oct 26, 2023
2ebb581
chore: cherry pick v2 coordinate mediation implementation
radleylewis Nov 1, 2023
8eeb407
fix: ensure tests passing post cherry pick
radleylewis Nov 1, 2023
a933f2c
refactor: shift isMediateDefaultGrantAll to message handler
radleylewis Nov 1, 2023
1089321
refactor: update docs and add constructor interface on CoordinateMedi…
radleylewis Nov 1, 2023
c8f9d56
feat: add "mediation-manager" plugin scaffold
radleylewis Nov 2, 2023
3f29efd
chore: install dependencies OK in mediation-manager
radleylewis Nov 2, 2023
2ea1c85
feat: add MedationManager methods
radleylewis Nov 2, 2023
3e7d865
feat: include MediationManager plugin in mediate cli
radleylewis Nov 2, 2023
9db1cfe
feat: build ok
radleylewis Nov 2, 2023
c9f596f
refactor: update cli mediate for kv-store
radleylewis Nov 3, 2023
69c31e3
fix: agent.yml mediationManager
radleylewis Nov 6, 2023
36c8d46
chore: prep delete migrations
radleylewis Nov 6, 2023
299babb
feat: working dbConnection
radleylewis Nov 6, 2023
e6cf8d7
refactor: strip out MediationPolicy from datastore
radleylewis Nov 7, 2023
0232ef6
chore: instantiate Mediation store
radleylewis Nov 7, 2023
3e950ac
refactor: add mediationManager methods
radleylewis Nov 7, 2023
fde1090
refactor: additional Mediation tests passing
radleylewis Nov 8, 2023
dd24794
fix: test passes on mediation DENIED
radleylewis Nov 8, 2023
a8aeebd
feat: add recipientDid methods to MedationManager
radleylewis Nov 8, 2023
3ea7c8c
refactor: remove RecipientDid logic from data-store
radleylewis Nov 8, 2023
0baa6ad
chore: skip query for now
radleylewis Nov 8, 2023
c9bdf0b
refactor: coordinate mediation v2 & v3 tests passing
radleylewis Nov 8, 2023
13d3da5
refactor: implement MediationManagerPlugin and reactivate tests
radleylewis Nov 8, 2023
68fd93f
refactor: shift mediationManagerIsMediationGranted
radleylewis Nov 8, 2023
4907bb0
refactor: mediation-manager.ts and IMediationManager name changes
radleylewis Nov 9, 2023
703a36b
refactor: update cli mediate for type changes
radleylewis Nov 9, 2023
b615018
refactor: updated types for Mediation, routing tests failing
radleylewis Nov 9, 2023
1b9cc88
chore: cleanup old mediation types on datastore, methods on client.yml
radleylewis Nov 9, 2023
cd36aed
chore: add agent.yml configuration for MediationManagerPlugin to READ…
radleylewis Nov 9, 2023
6b38ce5
fix: update tests for update recipient step
radleylewis Nov 9, 2023
c8df352
feat: ensure routing-message-handler-v2 backward compatibility
radleylewis Nov 9, 2023
79418ae
test: include routing message handler tests for coordinate mediation …
radleylewis Nov 9, 2023
c8572d5
test: use sqlite dbConnection for coordinate mediation v3 tests
radleylewis Nov 9, 2023
fd8dcb9
test: use sqlite dbConnection for coordinate mediation v3 tests
radleylewis Nov 9, 2023
70fcde3
fix: import kv-store from workspace in did-comm
radleylewis Nov 9, 2023
5e33867
chore: remove empty file
radleylewis Nov 10, 2023
ef68e20
feat: add IMediationManager methods documentation
radleylewis Nov 10, 2023
4ccee91
feat: add additional docs on IMedationManager
radleylewis Nov 10, 2023
30d5f51
feat: add type arguments on IMediationManager arg interfaces
radleylewis Nov 10, 2023
8caba06
chore: update MediationManager plugin README
radleylewis Nov 10, 2023
5f01d3f
chore: address warning on exported entitiesConcat fn
radleylewis Nov 10, 2023
820d28c
refactor: shift mediation-manager types from core-types to own plugin…
radleylewis Nov 22, 2023
a0db59a
fix: mediation-manager export documentation reference
radleylewis Nov 22, 2023
0aaba79
refactor: use TS private keyword instead of JS #
radleylewis Nov 22, 2023
e1a9760
chore: remove note on injecting grant or deny logic
radleylewis Nov 22, 2023
5c522ce
feat: implement list policies with kv-store iterator
radleylewis Nov 28, 2023
90d9420
feat: mediation-manager plugin listRecipientDids and RECIPIENT_QUERY …
radleylewis Nov 28, 2023
6f9124f
feat: add MediationManagerGetAllMediations to mediation-manager-plugin
radleylewis Nov 30, 2023
44f13ad
feat: add listResponses to mediate cli commands
radleylewis Nov 30, 2023
99dd99e
fix: kv-store iterator typing on mediation-manager
radleylewis Nov 30, 2023
bad7423
fix: RECIPIENT_QUERY response on available receipientDids
radleylewis Nov 30, 2023
a4d8e61
test: update RECIPIENT QUERY test to check that only recipientDids th…
radleylewis Nov 30, 2023
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
2 changes: 1 addition & 1 deletion __tests__/localAgent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ const setup = async (options?: IAgentOptions): Promise<boolean> => {
new SdrMessageHandler(),
],
}),
new DIDComm([new DIDCommHttpTransport()]),
new DIDComm({ transports: [new DIDCommHttpTransport()]}),
new CredentialPlugin(),
new CredentialIssuerEIP712(),
new CredentialIssuerLD({
Expand Down
2 changes: 1 addition & 1 deletion __tests__/restAgent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ const setup = async (options?: IAgentOptions): Promise<boolean> => {
new SdrMessageHandler(),
],
}),
new DIDComm([new DIDCommHttpTransport()]),
new DIDComm({ transports: [new DIDCommHttpTransport()]}),
// intentionally use the deprecated name to test compatibility
new CredentialIssuer(),
new CredentialIssuerEIP712(),
Expand Down
1 change: 1 addition & 0 deletions packages/cli/default/client.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,4 @@ agent:
- createSelectiveDisclosureRequest
- getVerifiableCredentialsForSdr
- validatePresentationAgainstSdr

2 changes: 2 additions & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,11 @@
"@veramo/message-handler": "workspace:^",
"@veramo/remote-client": "workspace:^",
"@veramo/remote-server": "workspace:^",
"@veramo/kv-store": "workspace:^",
"@veramo/selective-disclosure": "workspace:^",
"@veramo/url-handler": "workspace:^",
"@veramo/utils": "workspace:^",
"@veramo/mediation-manager": "workspace:^",
"blessed": "^0.1.81",
"commander": "^11.0.0",
"console-table-printer": "^2.11.2",
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/createCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { presentation } from './presentation.js'
import { explore } from './explore/index.js'
import { sdr } from './sdr.js'
import { server } from './server.js'
import { mediate } from './mediate.js'

const requireCjs = module.createRequire(import.meta.url)
const { version } = requireCjs('../package.json')
Expand All @@ -30,5 +31,6 @@ const veramo = new Command('veramo')
.addCommand(presentation)
.addCommand(sdr)
.addCommand(server)
.addCommand(mediate)

export { veramo }
201 changes: 201 additions & 0 deletions packages/cli/src/mediate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import { Command } from 'commander'
import inquirer from 'inquirer'

import { getAgent } from './setup.js'
import { PreMediationRequestPolicy, RecipientDid, RequesterDid } from '@veramo/mediation-manager'

type ConfiguredAgent = Awaited<ReturnType<typeof getAgent>>

const ALLOW = 'ALLOW'
const DENY = 'DENY'

type Options = Partial<{
granted: boolean
denied: boolean
allowFrom: boolean
denyFrom: boolean
interactive: boolean
fileJson: string
}>

type UpdatePolicyParams = {
dids: string[]
agent: ConfiguredAgent
policy?: PreMediationRequestPolicy
remove?: boolean
}

/**
* private functions
**/

const updatePolicies = async (options: UpdatePolicyParams): Promise<void> => {
const { dids, agent, policy, remove = false } = options
if (remove) {
return dids.forEach(
async (requesterDid) => await agent.mediationManagerRemoveMediationPolicy({ requesterDid }),
)
}
if (!policy) throw new Error('No policy provided')
return dids.forEach(
async (requesterDid) => await agent.mediationManagerSaveMediationPolicy({ requesterDid, policy }),
)
}

const promptForDids = async (action: string): Promise<string[]> => {
const { dids } = await inquirer.prompt<{ dids: string }>({
type: 'input',
name: 'dids',
message: `Enter the dids you want to ${action.toLowerCase()} separated by spaces:`,
})
return dids.split(' ')
}

/**
* cli action functions
**/

const policy = (policy: PreMediationRequestPolicy) => {
return async function (
{ fileJson, interactive }: Pick<Options, 'fileJson' | 'interactive'>,
cmd: Command,
): Promise<void> {
try {
if (fileJson && interactive) throw new Error('Please specify only one input method')

const agent = await getAgent(cmd.optsWithGlobals().config)
console.log('AGENT CREATED')

if (fileJson) {
const jsonData = await import(fileJson, { assert: { type: 'json' } })
const dids = jsonData.default
await updatePolicies({ dids, agent, policy })
} else if (interactive) {
const dids = await promptForDids(policy)
await updatePolicies({ dids, agent, policy })
} else {
const dids = cmd.args
await updatePolicies({ dids, agent, policy })
}

console.log('Mediation policies updated')
} catch (e) {
console.error(e.message)
}
}
}

async function readPolicies(options: Pick<Options, 'interactive' | 'fileJson'>, cmd: Command): Promise<void> {
const agent = await getAgent(cmd.optsWithGlobals().config)
let dids: string[]
if (options.interactive) dids = await promptForDids('read')
else if (options.fileJson) dids = (await import(options.fileJson, { assert: { type: 'json' } })).default
else dids = cmd.args
if (!dids || !dids.length) throw new Error('No dids provided')
const policies: Record<RequesterDid, RecipientDid | null> = {}
for await (const requesterDid of dids) {
policies[requesterDid] = await agent.mediationManagerGetMediationPolicy({ requesterDid })
}
console.log('POLICIES')
console.table(policies)
}

async function listPolicies(options: Pick<Options, 'allowFrom' | 'denyFrom'>, cmd: Command): Promise<void> {
try {
const agent = await getAgent(cmd.optsWithGlobals().config)
const res = await agent.mediationManagerListMediationPolicies()
console.log('POLICIES')
if (options.allowFrom) return console.table(Object.entries(res).filter(([, policy]) => policy === ALLOW))
if (options.denyFrom) return console.table(Object.entries(res).filter(([, policy]) => policy === DENY))
else console.table(res)
} catch (e) {
console.error(e.message)
}
}

async function listResponses(
{ granted, denied }: Pick<Options, 'granted' | 'denied'>,
cmd: Command,
): Promise<void> {
try {
const agent = await getAgent(cmd.optsWithGlobals().config)
const res = await agent.mediationManagerGetAllMediations()
console.log('MEDIATIONS')
if (granted) return console.table(Object.entries(res).filter(([, response]) => response === 'GRANTED'))
if (denied) return console.table(Object.entries(res).filter(([, response]) => response === 'DENIED'))
else console.table(res)
} catch (e) {
console.error(e.message)
}
}

async function removePolicies(
{ fileJson, interactive }: Pick<Options, 'fileJson' | 'interactive'>,
cmd: Command,
): Promise<void> {
try {
const agent = await getAgent(cmd.optsWithGlobals().config)

if (fileJson) {
const jsonData = await import(fileJson, { assert: { type: 'json' } })
const dids = jsonData.default
await updatePolicies({ dids, remove: true, agent })
} else if (interactive) {
const dids = await promptForDids('Remove')
await updatePolicies({ dids, remove: true, agent })
} else {
const dids = cmd.args
await updatePolicies({ dids, remove: true, agent })
}

console.log('Mediation policies removed')
} catch (e) {
console.error(e.message)
}
}

const mediate = new Command('mediate').description('Mediate allow or deny policy on dids')

mediate
.command('allow-from')
.description('add dids that should be allowed for mediation')
.option('-f, --file-json <string>', 'read dids from json file')
.option('-i, --interactive', 'interactively input dids')
.action(policy(ALLOW))

mediate
.command('deny-from')
.description('deny dids that should be denied for mediation')
.option('-f, --file-json <string>', 'read dids from json file')
.option('-i, --interactive', 'interactively input dids')
.action(policy(DENY))

mediate
.command('read')
.description('read mediation policy for a specific did')
.option('-i, --interactive', 'interactively input dids')
.option('-f, --file-json <string>', 'read dids from json file')
.action(readPolicies)

mediate
.command('list-policies')
.description('list mediation policies')
.option('-a, --allow-from', 'list allow policies')
.option('-d, --deny-from', 'list deny policies')
.action(listPolicies)

mediate
.command('list-responses')
.description('list mediation responses')
.option('-a, --granted', 'list granted policies')
.option('-d, --denied', 'list denied policies')
.action(listResponses)

mediate
.command('remove')
.description('remove mediation policies')
.option('-f, --file-json <string>', 'read dids from json file')
.option('-i, --interactive', 'interactively input dids')
.action(removePolicies)

export { mediate }
7 changes: 6 additions & 1 deletion packages/cli/src/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import {
IResolver,
TAgent,
} from '@veramo/core-types'
import {
IMediationManager,

} from "@veramo/mediation-manager"
import { ISelectiveDisclosure } from '@veramo/selective-disclosure'
import { IDIDComm } from '@veramo/did-comm'
import { IDIDDiscovery } from '@veramo/did-discovery'
Expand Down Expand Up @@ -57,7 +61,8 @@ export type EnabledInterfaces = IDIDManager &
IDIDComm &
ICredentialPlugin &
ISelectiveDisclosure &
IDIDDiscovery
IDIDDiscovery &
IMediationManager

export type ConfiguredAgent = TAgent<EnabledInterfaces>

Expand Down
19 changes: 10 additions & 9 deletions packages/data-store-json/src/data-store-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ export class DataStoreJson implements IAgentPlugin {
dataStoreDeleteVerifiableCredential: this.dataStoreDeleteVerifiableCredential.bind(this),
dataStoreSaveVerifiablePresentation: this.dataStoreSaveVerifiablePresentation.bind(this),
dataStoreGetVerifiablePresentation: this.dataStoreGetVerifiablePresentation.bind(this),
//dataStoreDeleteVerifiablePresentation: this.dataStoreDeleteVerifiablePresentation.bind(this),

// IDataStoreORM methods
dataStoreORMGetIdentifiers: this.dataStoreORMGetIdentifiers.bind(this),
Expand Down Expand Up @@ -295,13 +294,15 @@ export class DataStoreJson implements IAgentPlugin {
expirationDate = new Date(vp.expirationDate)
}

const credentials: VerifiableCredential[] = asArray(vp.verifiableCredential).map((cred: W3CVerifiableCredential) => {
if (typeof cred === 'string') {
return normalizeCredential(cred)
} else {
return <VerifiableCredential>cred
}
})
const credentials: VerifiableCredential[] = asArray(vp.verifiableCredential).map(
(cred: W3CVerifiableCredential) => {
if (typeof cred === 'string') {
return normalizeCredential(cred)
} else {
return <VerifiableCredential>cred
}
},
)

const presentation: PresentationTableEntry = {
hash,
Expand Down Expand Up @@ -617,7 +618,7 @@ function buildQuery<T extends Partial<Record<PossibleColumns, any>>>(
filteredCollection = filteredCollection.slice(input.skip)
}
if (input.take) {
const start = input.skip && input.skip - 1 || 0
const start = (input.skip && input.skip - 1) || 0
const end = start + input.take
filteredCollection = filteredCollection.slice(start, end)
}
Expand Down
12 changes: 6 additions & 6 deletions packages/data-store/src/data-store-orm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export class DataStoreORM implements IAgentPlugin {

private async identifiersQuery(
args: FindArgs<TIdentifiersColumns>,
context: AuthorizedDIDContext,
context?: AuthorizedDIDContext,
): Promise<SelectQueryBuilder<Identifier>> {
const where = createWhereObject(args)
let qb = (await getConnectedDb(this.dbConnection))
Expand All @@ -101,7 +101,7 @@ export class DataStoreORM implements IAgentPlugin {
args: FindArgs<TIdentifiersColumns>,
context: AuthorizedDIDContext,
): Promise<PartialIdentifier[]> {
const identifiers = await (await this.identifiersQuery(args, context)).getMany()
const identifiers = await (await this.identifiersQuery(args)).getMany()
return identifiers.map((i) => {
const identifier: PartialIdentifier = i as PartialIdentifier
if (identifier.controllerKeyId === null) {
Expand Down Expand Up @@ -416,11 +416,11 @@ function decorateQB(

if (input?.order) {
for (const item of input.order) {
qb = qb.addSelect(qb.connection.driver.escape(tableName) + '.' + qb.connection.driver.escape(item.column), item.column)
qb = qb.orderBy(
qb.connection.driver.escape(item.column),
item.direction,
qb = qb.addSelect(
qb.connection.driver.escape(tableName) + '.' + qb.connection.driver.escape(item.column),
item.column,
)
qb = qb.orderBy(qb.connection.driver.escape(item.column), item.direction)
}
}
return qb
Expand Down
12 changes: 11 additions & 1 deletion packages/data-store/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ export const Entities = [
PrivateKey,
PreMigrationKey,
]

/**
* Helper function to concatenate multiple arrays of TypeORM entities.
*
* This array CAN be used when creating a TypeORM connection.
*
* @public
*/
export const entitiesConcat = (...entityArrays: unknown[][]) =>
entityArrays.reduce((acc, entityArray) => acc.concat(entityArray), [])
export {
KeyType,
Key,
Expand All @@ -56,7 +66,7 @@ export {
PrivateKey,
PreMigrationKey,
}
export { migrations } from './migrations/index.js'
export { migrations, migrationConcat } from './migrations/index.js'

// re-export the interfaces that were moved to core for backward compatibility
export { IDataStore, IDataStoreORM } from '@veramo/core-types'
5 changes: 2 additions & 3 deletions packages/data-store/src/migrations/1.createDatabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ const debug = Debug('veramo:data-store:initial-migration')
* @public
*/
export class CreateDatabase1447159020001 implements MigrationInterface {

name = 'CreateDatabase1447159020001' // Used in case this class gets minified, which would change the classname

async up(queryRunner: QueryRunner): Promise<void> {
Expand All @@ -21,7 +20,7 @@ export class CreateDatabase1447159020001 implements MigrationInterface {
// "CREATE UNIQUE INDEX \"IDX_6098cca69c838d91e55ef32fe1\" ON \"identifier\" (\"alias\", \"provider\")",
await queryRunner.createTable(
new Table({
name: migrationGetTableName(queryRunner,'identifier'),
name: migrationGetTableName(queryRunner, 'identifier'),
columns: [
{ name: 'did', type: 'varchar', isPrimary: true },
{ name: 'provider', type: 'varchar', isNullable: true },
Expand All @@ -44,7 +43,7 @@ export class CreateDatabase1447159020001 implements MigrationInterface {
// "CREATE TABLE \"key\" (\"kid\" varchar PRIMARY KEY NOT NULL, \"kms\" varchar NOT NULL, \"type\" varchar NOT NULL, \"publicKeyHex\" varchar NOT NULL, \"privateKeyHex\" varchar NOT NULL, \"meta\" text, \"identifierDid\" varchar, CONSTRAINT \"FK_3f40a9459b53adf1729dbd3b787\" FOREIGN KEY (\"identifierDid\") REFERENCES \"identifier\" (\"did\") ON DELETE NO ACTION ON UPDATE NO ACTION)",
await queryRunner.createTable(
new Table({
name: migrationGetTableName(queryRunner,'key'),
name: migrationGetTableName(queryRunner, 'key'),
columns: [
{ name: 'kid', type: 'varchar', isPrimary: true },
{ name: 'kms', type: 'varchar' },
Expand Down
Loading