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(core): connection-less issuance and verification #359

Merged
merged 22 commits into from
Jul 22, 2021

Conversation

TimoGlastra
Copy link
Contributor

@TimoGlastra TimoGlastra commented Jul 3, 2021

Adds connection-less issuance and verification.

  • Agent.credentials.createOutOfBandOffer - to create credential offer not bound to connection
  • Agent.proofs.createOutOfBandRequest - to create presentation request not bound to connection
  • Add ~service decorator

Required more changes than initially thought because I had to remove the required connection parameter everywhere.

Fixes #347
Fixes #346

@TimoGlastra TimoGlastra requested a review from a team as a code owner July 3, 2021 15:15
@codecov-commenter
Copy link

codecov-commenter commented Jul 3, 2021

Codecov Report

Merging #359 (707034e) into main (d84acc7) will increase coverage by 0.10%.
The diff coverage is 83.12%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #359      +/-   ##
==========================================
+ Coverage   86.52%   86.62%   +0.10%     
==========================================
  Files         246      248       +2     
  Lines        5010     5198     +188     
  Branches      788      827      +39     
==========================================
+ Hits         4335     4503     +168     
- Misses        675      695      +20     
Impacted Files Coverage Δ
packages/core/src/agent/TransportService.ts 92.30% <ø> (ø)
packages/core/src/index.ts 100.00% <ø> (ø)
...modules/credentials/repository/CredentialRecord.ts 91.22% <0.00%> (-3.32%) ⬇️
.../core/src/modules/proofs/repository/ProofRecord.ts 85.36% <0.00%> (-4.38%) ⬇️
...ages/core/src/transport/HttpOutboundTransporter.ts 12.50% <0.00%> (ø)
...ckages/core/src/transport/WsOutboundTransporter.ts 5.26% <0.00%> (-0.10%) ⬇️
packages/core/src/types.ts 100.00% <ø> (ø)
...les/credentials/handlers/OfferCredentialHandler.ts 65.51% <50.00%> (-23.96%) ⬇️
packages/core/src/agent/MessageSender.ts 74.22% <65.21%> (-13.62%) ⬇️
...les/credentials/handlers/IssueCredentialHandler.ts 95.45% <90.00%> (+5.98%) ⬆️
... and 28 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d84acc7...707034e. Read the comment docs.

Copy link
Contributor

@berendsliedrecht berendsliedrecht left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think connectionless instead of connection-less might be better.

@TimoGlastra
Copy link
Contributor Author

I think connectionless instead of connection-less might be better.

I used the notation as used in the Aries RFCs: https://github.com/hyperledger/aries-rfcs/search?q=connection-less

@TimoGlastra
Copy link
Contributor Author

Ah but seems google like connectionless better

@berendsliedrecht
Copy link
Contributor

I think connectionless instead of connection-less might be better.

I used the notation as used in the Aries RFCs: https://github.com/hyperledger/aries-rfcs/search?q=connection-less

Ah yeah that makes sense then.

@JamesKEbert
Copy link
Contributor

This is awesome, I have not given this a thoroooough review yet, but I wanted to gauge/express concern over the naming on createOutOfBandOffer, since it could cause confusion/collision with the Out Of Band (OOB) invitations? What are your thoughts here @TimoGlastra?

@TimoGlastra
Copy link
Contributor Author

TimoGlastra commented Jul 14, 2021

This is awesome, I have not given this a thoroooough review yet, but I wanted to gauge/express concern over the naming on createOutOfBandOffer, since it could cause confusion/collision with the Out Of Band (OOB) invitations? What are your thoughts here @TimoGlastra?

I actually think it matches perfectly with the OOB protocol. Out-Of-Band is a protocol to facilitate out-of-band exchange of messages. ACA-Py has it as a separate out-of-band topic but IMO it makes more sense to house them under the different modules. If we adopt OOB and want to issue a connectionless credentials, we can call the credentials module, which will actually return an OOB message with a credential offer inside of it.

I think we can abstract the OOB protocol mostly away unless you have very specific requirements besides connection invitations, connectionless issuance/verification. Does my thinking make sense?

@JamesKEbert
Copy link
Contributor

I tend to agree with you here actually. I think having a separate module/service here for Out-Of-Band messages would be helpful, since it can do the bulk of the formatting and any needed storage (for non-connectionless). However I think other modules being able to use Out-Of-Band messages as you've outlined makes sense (essentially initiating the offer, but then collaborating with the OOB module to create the message).
So, in short I agree with your thought process here @TimoGlastra.

Copy link
Contributor

@JamesKEbert JamesKEbert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me--I would like to take another look after your updates here, specifically given some transport and mediation changes that I think are likely relevant.

@TimoGlastra TimoGlastra changed the title feat: support connection-less issuance and verification feat(core): connection-less issuance and verification Jul 17, 2021
Signed-off-by: Timo Glastra <[email protected]>
Signed-off-by: Timo Glastra <[email protected]>
@TimoGlastra
Copy link
Contributor Author

This looks good to me--I would like to take another look after your updates here, specifically given some transport and mediation changes that I think are likely relevant.

@JamesKEbert Updated

@TimoGlastra
Copy link
Contributor Author

It was quite a hassle to merge. I think some pieces could be handled better, but I'd like to handle that in separate PRs and have some discussions about it first. Mainly:

  • With auto accept merged, I had to duplicate quite some code between handler and module because they do a lot of the same stuff.
  • Message sender is becoming quite complex. I think it's unavoidable, but would be good to streamline it as much as possible. We can now send unpacked messages, packed messages, and also connection-less messages. All have overlap but all have differences.
  • Connection less requires quite some code in the module / handlers. I would like to look at a way to reduce this and just let it be handled by the router / messaging / packing logic. However I think we can do this best in combination with out-of-band.

So I'd like to merge in this state and make additional improvements in the future

filter((e) => state === undefined || e.payload.proofRecord.state === state),
timeout(timeoutMs),
catchError(() => {
throw new Error(`ProofStateChanged event not emitted within specified timeout: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error message string is a little bit harder to read. Wouldn't be better to pass such info as an object into error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error doesn't take additional arguments

packages/core/src/agent/MessageSender.ts Outdated Show resolved Hide resolved
messageSender.setOutboundTransporter(outboundTransporter)
transportServiceFindServicesMock.mockReturnValue([])

await expect(messageSender.sendMessage(outboundMessage)).rejects.toThrow(
`Connection with id test-123 has no service!`
`Message is undeliverable to connection test-123 (Test 123)`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if theirLabel contains some malicious code? Are we protected against that? I'm not sure if it's safe to use theirLabel anywhere in the code 🤔

Copy link
Contributor Author

@TimoGlastra TimoGlastra Jul 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that could cause any harm? thread id is also external. You mean like eval() harm?

I'm not sure what makes this property different from the others. We're not doing any SQL / HTTP rendering

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, sorry I was probably confused remembering some call where there was a discussion about the security of invitations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be better to use connection.label in such cases instead? I'm also a little bit confused what's the case for label and theirLabel 🤔 😄

await this.messageSender.sendMessage(outboundMessage)
}
// Use ~service decorator otherwise
else if (credentialRecord.credentialMessage?.service && credentialRecord.requestMessage?.service) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if it's good to write if statements in this way. It seems like a convention from C# but not common in JS language. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else#using_else_if

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I fully understand. I've never heard that else if is an anti-pattern in JS.

However I'm that a big fan of this code. The if/else shouldn't be there in the first place. But until out-of-band I'd like to keep it there

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean this

    }
    // Use ~service decorator otherwise
    else if 

instead of

    } else if {
      // Use ~service decorator otherwise
    }

Comment on lines +180 to +188
const nonce = proofRequestOptions.nonce ?? (await this.proofService.generateProofRequestNonce())

const proofRequest = new ProofRequest({
name: proofRequestOptions.name ?? 'proof-request',
version: proofRequestOptions.name ?? '1.0',
nonce,
requestedAttributes: proofRequestOptions.requestedAttributes,
requestedPredicates: proofRequestOptions.requestedPredicates,
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be part of proofService.createRequest service? It seems like duplication from another method calling proofService.createRequest

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't want to make opinions about default values in the service. I'm not even sure we should set default values...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So for now I'd like to keep it in the module (and have a discussion about the duplication during the AFJ call)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok


return { proofRecord, requestMessage: message }
}

/**
* Accept a presentation request as prover (by sending a presentation message) to the connection
* associated with the proof record.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I built JS doc blindness so I usually don't read it so much :) but I'm not sure if it's updated according to the changes.

const credentialRecordPromise = waitForCredentialRecord(holderAgent, {
threadId: issuerCredentialRecord.threadId,
state: CredentialState.OfferReceived,
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any benefit of making a Promise variable rather than awating it later at line 400?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm in the progress of refactoring the method to work with observables. We need to start listening before calling the method that will emit the event. Otherwise we start listening potentially after the event has already been emitted. So we need to start the listener, make the function call and then await.

I've partly refactored some other call to use ReplaySubject so we can replay all events that came in.

@jakubkoci
Copy link
Contributor

jakubkoci commented Jul 20, 2021

I added a few notes, but it seems good overall 👍 I believe we're able to improve MessageSender. There is a lot of small duplication all over the class. It was hard for me to get oriented.

@TimoGlastra
Copy link
Contributor Author

There is a lot of small duplication all over the class. It was hard for me to get oriented.

Definitely would like to improve the duplication in message sender

@JamesKEbert
Copy link
Contributor

I tend to agree on the complexity of the message sender, but I think I'm comfortable improving on that in subsequent PRs.

Connection less requires quite some code in the module / handlers. I would like to look at a way to reduce this and just let it be handled by the router / messaging / packing logic. However I think we can do this best in combination with out-of-band.

I think this is an important item/consideration ^

Copy link
Contributor

@jakubkoci jakubkoci left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to merge it before adding support for mulitransports. It seems there is quite some logic in the same area.

@TimoGlastra TimoGlastra linked an issue Jul 22, 2021 that may be closed by this pull request
@TimoGlastra TimoGlastra enabled auto-merge (squash) July 22, 2021 22:07
@TimoGlastra TimoGlastra disabled auto-merge July 22, 2021 22:07
@TimoGlastra TimoGlastra enabled auto-merge (squash) July 22, 2021 22:08
@TimoGlastra TimoGlastra disabled auto-merge July 22, 2021 22:08
@TimoGlastra TimoGlastra enabled auto-merge (squash) July 22, 2021 22:08
@TimoGlastra TimoGlastra merged commit fb46ade into openwallet-foundation:main Jul 22, 2021
@TimoGlastra TimoGlastra deleted the feat/conectionless branch October 28, 2021 10:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants