Skip to content

Commit

Permalink
Support invitation messages with public DID (#340)
Browse files Browse the repository at this point in the history
Implement public DID invitations

Signed-off-by: Miroslav Kovar <miroslavkovar@protonmail.com>
  • Loading branch information
mirgee authored Sep 1, 2021
1 parent 1b11be2 commit 865ffc9
Show file tree
Hide file tree
Showing 41 changed files with 1,245 additions and 92 deletions.
1 change: 1 addition & 0 deletions agency_client/src/payload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ pub enum PayloadKinds {
Cred,
Proof,
ProofRequest,
ConnRequest,
Other(String),
}
5 changes: 3 additions & 2 deletions agents/node/vcxagent-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,14 @@
"demo:faber:pg": "node demo/faber.js --postgresql",
"demo:alice:sign": "node demo/alice-signature.js",
"demo:faber:verify": "node demo/faber-verify-signature.js",
"test:integration": "npm run test:integration:update-state && npm run test:integration:signing && npm run test:integration:messaging && npm run test:integration:tails && npm run test:integration:trustping && npm run test:integration:feature-discovery",
"test:integration": "npm run test:integration:update-state && npm run test:integration:signing && npm run test:integration:messaging && npm run test:integration:tails && npm run test:integration:trustping && npm run test:integration:feature-discovery && npm run test:integration:public-invite",
"test:integration:update-state": "jest --forceExit --env=node --runInBand test/update-state-v2.spec.js",
"test:integration:signing": "jest --forceExit --env=node --runInBand test/sign-verify.spec.js",
"test:integration:messaging": "jest --forceExit --env=node --runInBand test/sign-messaging.spec.js",
"test:integration:tails": "jest --forceExit --env=node --runInBand test/distribute-tails.spec.js",
"test:integration:trustping": "jest --forceExit --env=node --runInBand test/trustping.spec.js",
"test:integration:feature-discovery": "jest --forceExit --env=node --runInBand test/feature-discovery.spec.js"
"test:integration:feature-discovery": "jest --forceExit --env=node --runInBand test/feature-discovery.spec.js",
"test:integration:public-invite": "jest --forceExit --env=node --runInBand test/public-invite.spec.js"
},
"dependencies": {
"axios": "^0.21.1",
Expand Down
16 changes: 13 additions & 3 deletions agents/node/vcxagent-core/src/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const { createServiceProver } = require('./services/service-prover')
const { createServiceCredHolder } = require('./services/service-cred-holder')
const { createServiceCredIssuer } = require('./services/service-cred-issuer')
const { createServiceConnections } = require('./services/service-connections')
const { createServiceAgents } = require('./services/service-agents')
const { provisionAgentInAgency } = require('./utils/vcx-workflows')
const {
initThreadpool,
Expand All @@ -14,7 +15,7 @@ const {
openMainWallet,
openMainPool,
vcxUpdateWebhookUrl,
shutdownVcx,
shutdownVcx
} = require('@hyperledger/node-vcx-wrapper')
const { createStorageService } = require('./storage/storage-service')
const { waitUntilAgencyIsReady } = require('./common')
Expand Down Expand Up @@ -67,13 +68,14 @@ async function createVcxAgent ({ agentName, genesisPath, agencyUrl, seed, usePos
}

function getInstitutionDid () {
return agentProvision.institution_did
return issuerDid
}

const serviceConnections = createServiceConnections({
logger,
saveConnection: storageService.saveConnection,
loadConnection: storageService.loadConnection,
loadAgent: storageService.loadAgent,
listConnectionIds: storageService.listConnectionKeys
})
const serviceLedgerSchema = createServiceLedgerSchema({
Expand Down Expand Up @@ -118,6 +120,11 @@ async function createVcxAgent ({ agentName, genesisPath, agencyUrl, seed, usePos
loadProof: storageService.loadProof,
listProofIds: storageService.listProofKeys
})
const serviceAgent = createServiceAgents({
logger,
saveAgent: storageService.saveAgent,
loadAgent: storageService.loadAgent
})

return {
// vcx controls
Expand All @@ -140,7 +147,10 @@ async function createVcxAgent ({ agentName, genesisPath, agencyUrl, seed, usePos

// proofs
serviceProver,
serviceVerifier
serviceVerifier,

// agents
serviceAgent
}
}

Expand Down
30 changes: 30 additions & 0 deletions agents/node/vcxagent-core/src/services/service-agents.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const {
Agent
} = require('@hyperledger/node-vcx-wrapper')

module.exports.createServiceAgents = function createServiceAgents ({ logger, saveAgent, loadAgent }) {
async function publicAgentCreate (agentId, institutionDid) {
logger.info(`Creating public agent with id ${agentId} for institution did ${institutionDid}`)
const agent = await Agent.create(agentId, institutionDid)
await saveAgent(agentId, agent)
return agent
}

async function getPublicInvite (agentId, label) {
logger.info(`Public agent with id ${agentId} is creating public invite with label ${label}`)
const agent = await loadAgent(agentId)
return agent.generatePublicInvite(label)
}

async function downloadConnectionRequests (agentId) {
logger.info(`Public agent with id ${agentId} is downloading connection requests`)
const agent = await loadAgent(agentId)
return agent.downloadConnectionRequests()
}

return {
publicAgentCreate,
getPublicInvite,
downloadConnectionRequests
}
}
18 changes: 15 additions & 3 deletions agents/node/vcxagent-core/src/services/service-connections.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ const { getMessagesForConnection } = require('../utils/messages')
const {
updateMessages,
Connection,
ConnectionStateType
ConnectionStateType,
} = require('@hyperledger/node-vcx-wrapper')
const { pollFunction } = require('../common')

module.exports.createServiceConnections = function createServiceConnections ({ logger, saveConnection, loadConnection, listConnectionIds }) {
module.exports.createServiceConnections = function createServiceConnections ({ logger, saveConnection, loadConnection, loadAgent, listConnectionIds }) {
async function inviterConnectionCreate (connectionId, cbInvitation) {
logger.info(`InviterConnectionSM creating connection ${connectionId}`)
const connection = await Connection.create({ id: connectionId })
Expand All @@ -22,6 +22,18 @@ module.exports.createServiceConnections = function createServiceConnections ({ l
return invite
}

async function inviterConnectionCreateFromRequest (connectionId, agentId, request) {
logger.info(`InviterConnectionSM creating connection ${connectionId} from received request ${request} and agent id ${agentId}`)
const agent = await loadAgent(agentId)
const connection = await Connection.createWithConnectionRequest({
id: connectionId,
agent,
request
})
await saveConnection(connectionId, connection)
return connection
}

async function inviterConnectionCreateAndAccept (conenctionId, cbInvitation) {
const invite = await inviterConnectionCreate(conenctionId, cbInvitation)
const connection = await loadConnection(conenctionId)
Expand Down Expand Up @@ -162,10 +174,10 @@ module.exports.createServiceConnections = function createServiceConnections ({ l
await connection.sendDiscoveryFeatures()
}


return {
// inviter
inviterConnectionCreate,
inviterConnectionCreateFromRequest,
inviterConnectionCreateAndAccept,

// invitee
Expand Down
20 changes: 19 additions & 1 deletion agents/node/vcxagent-core/src/storage/storage-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ const {
CredentialDef,
Schema,
DisclosedProof,
Proof
Proof,
Agent
} = require('@hyperledger/node-vcx-wrapper')

async function createStorageService (agentName) {
Expand All @@ -24,6 +25,7 @@ async function createStorageService (agentName) {
const storageDisclosedProof = await createFileStorage(`storage-dislosedProofs/${agentName}`)
const storageCredentialDefinitons = await createFileStorage(`storage-credentialDefinitions/${agentName}`)
const storageSchemas = await createFileStorage(`storage-schemas/${agentName}`)
const storageAgents = await createFileStorage(`storage-agents/${agentName}`)

async function agentProvisionExists () {
return storageAgentProvisions.hasKey('agent-provision')
Expand Down Expand Up @@ -128,6 +130,19 @@ async function createStorageService (agentName) {
return Proof.deserialize(serialized)
}

async function saveAgent (name, agent) {
const serialized = await agent.serialize()
await storageAgents.set(name, serialized)
}

async function loadAgent (name) {
const serialized = await storageAgents.get(name)
if (!serialized) {
throw Error(`Agent ${name} was not found.`)
}
return Agent.deserialize(serialized)
}

async function listConnectionKeys () {
return storageConnections.keys()
}
Expand Down Expand Up @@ -182,6 +197,9 @@ async function createStorageService (agentName) {
saveProof,
loadProof,

saveAgent,
loadAgent,

listConnectionKeys,
listSchemaKeys,
listCredentialDefinitionKeys,
Expand Down
2 changes: 1 addition & 1 deletion agents/node/vcxagent-core/src/utils/messages.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { downloadMessages, downloadMessagesV2 } = require('@hyperledger/node-vcx-wrapper')
const { downloadMessages, downloadMessagesV2, downloadAllMessages } = require('@hyperledger/node-vcx-wrapper')
const _ = require('lodash')

async function maybeJoinWithComma (list) {
Expand Down
35 changes: 35 additions & 0 deletions agents/node/vcxagent-core/test/public-invite.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* eslint-env jest */
require('jest')
const { createPairedAliceAndFaberViaPublicInvite } = require('./utils/utils')
const { initRustapi } = require('../src/index')

beforeAll(async () => {
jest.setTimeout(1000 * 60 * 4)
await initRustapi(process.env.VCX_LOG_LEVEL || 'vcx=error')
})

describe('test public invite', () => {
it('Establish connection via public invite, exchange messages', async () => {
const { alice, faber } = await createPairedAliceAndFaberViaPublicInvite()

await alice.sendMessage('Hello Faber')
const msgsFaber = await faber.downloadReceivedMessagesV2()
expect(msgsFaber.length).toBe(1)
expect(msgsFaber[0].uid).toBeDefined()
expect(msgsFaber[0].statusCode).toBe('MS-103')
const payloadFaber = JSON.parse(msgsFaber[0].decryptedMsg)
expect(payloadFaber['@id']).toBeDefined()
expect(payloadFaber['@type']).toBeDefined()
expect(payloadFaber.content).toBe('Hello Faber')

await faber.sendMessage('Hello Alice')
const msgsAlice = await alice.downloadReceivedMessagesV2()
expect(msgsAlice.length).toBe(1)
expect(msgsAlice[0].uid).toBeDefined()
expect(msgsAlice[0].statusCode).toBe('MS-103')
const payloadAlice = JSON.parse(msgsAlice[0].decryptedMsg)
expect(payloadAlice['@id']).toBeDefined()
expect(payloadAlice['@type']).toBeDefined()
expect(payloadAlice.content).toBe('Hello Alice')
})
})
2 changes: 1 addition & 1 deletion agents/node/vcxagent-core/test/utils/alice.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ module.exports.createAlice = async function createAlice () {
const vcxAgent = await createVcxAgent(aliceAgentConfig)

async function acceptInvite (invite) {
logger.info('Alice establishing connection with Faber')
logger.info(`Alice establishing connection with Faber using invite ${invite}`)

await vcxAgent.agentInitVcx()

Expand Down
42 changes: 42 additions & 0 deletions agents/node/vcxagent-core/test/utils/faber.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module.exports.createFaber = async function createFaber () {
const agentName = `faber-${Math.floor(new Date() / 1000)}`
const connectionId = 'connection-faber-to-alice'
const issuerCredId = 'credential-for-alice'
const agentId = 'faber-public-agent'
let credDefId
const proofId = 'proof-from-alice'
const logger = require('../../demo/logger')('Faber')
Expand Down Expand Up @@ -37,6 +38,19 @@ module.exports.createFaber = async function createFaber () {
return invite
}

async function createPublicInvite () {
logger.info('Faber is going to generate public invite')
await vcxAgent.agentInitVcx()

await vcxAgent.serviceAgent.publicAgentCreate(agentId, vcxAgent.getInstitutionDid())
const invite = await vcxAgent.serviceAgent.getPublicInvite(agentId, 'faber-label')
logger.info(`Faber generated public invite:\n${invite}`)

await vcxAgent.agentShutdownVcx()

return invite
}

async function sendConnectionResponse () {
logger.info('Faber is going to generate invite')
await vcxAgent.agentInitVcx()
Expand Down Expand Up @@ -137,6 +151,24 @@ module.exports.createFaber = async function createFaber () {
return agencyMessages
}

async function _downloadConnectionRequests () {
logger.info('Faber is going to download connection requests')
const connectionRequests = await vcxAgent.serviceAgent.downloadConnectionRequests(agentId)
logger.info(`Downloaded connection requests: ${connectionRequests}`)
return JSON.parse(connectionRequests)
}

async function createConnectionFromReceivedRequest () {
logger.info('Faber is going to download connection requests')
await vcxAgent.agentInitVcx()

const requests = await _downloadConnectionRequests()
await vcxAgent.serviceConnections.inviterConnectionCreateFromRequest(connectionId, agentId, JSON.stringify(requests[0]))
expect(await vcxAgent.serviceConnections.connectionUpdate(connectionId)).toBe(ConnectionStateType.Responded)

await vcxAgent.agentShutdownVcx()
}

async function updateMessageStatus (uids) {
await vcxAgent.agentInitVcx()
await vcxAgent.serviceConnections.updateMessagesStatus(connectionId, uids)
Expand Down Expand Up @@ -184,11 +216,21 @@ module.exports.createFaber = async function createFaber () {
return tailsHash
}

async function sendMessage (message) {
logger.info('Faber is going to send message')
await vcxAgent.agentInitVcx()
await vcxAgent.serviceConnections.sendMessage(connectionId, message)
await vcxAgent.agentShutdownVcx()
}

return {
downloadReceivedMessages,
downloadReceivedMessagesV2,
sendMessage,
verifySignature,
createInvite,
createPublicInvite,
createConnectionFromReceivedRequest,
updateConnection,
sendConnectionResponse,
sendCredentialOffer,
Expand Down
11 changes: 11 additions & 0 deletions agents/node/vcxagent-core/test/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,14 @@ module.exports.createPairedAliceAndFaber = async function createPairedAliceAndFa
await faber.updateConnection(ConnectionStateType.Finished)
return { alice, faber }
}

module.exports.createPairedAliceAndFaberViaPublicInvite = async function createPairedAliceAndFaberViaPublicInvite () {
const alice = await createAlice()
const faber = await createFaber()
const invite = await faber.createPublicInvite()
await alice.acceptInvite(invite)
await faber.createConnectionFromReceivedRequest()
await alice.updateConnection(ConnectionStateType.Finished)
await faber.updateConnection(ConnectionStateType.Finished)
return { alice, faber }
}
12 changes: 12 additions & 0 deletions aries_vcx/src/handlers/connection/cloud_agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,18 @@ impl CloudAgentInfo {
.map_err(|err| err.into())
}

pub fn reject_message(&self, pairwise_info: &PairwiseInfo, uid: String) -> VcxResult<()> {
trace!("CloudAgentInfo::reject_message >>> uid: {:?}", uid);

let messages_to_reject = vec![UIDsByConn {
pairwise_did: pairwise_info.pw_did.clone(),
uids: vec![uid],
}];

update_messages_status(MessageStatusCode::Rejected, messages_to_reject)
.map_err(|err| err.into())
}

pub fn download_encrypted_messages(&self, msg_uid: Option<Vec<String>>, status_codes: Option<Vec<MessageStatusCode>>, pairwise_info: &PairwiseInfo) -> VcxResult<Vec<Message>> {
trace!("CloudAgentInfo::download_encrypted_messages >>>");
get_connection_messages(&pairwise_info.pw_did, &pairwise_info.pw_vk, &self.agent_did, &self.agent_vk, msg_uid, status_codes)
Expand Down
Loading

0 comments on commit 865ffc9

Please sign in to comment.