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

Implement PresentationDefinition field filter schema #102

Merged
merged 15 commits into from
Oct 27, 2023

Conversation

phoebe-lew
Copy link
Contributor

No description provided.

- refactor satisfiesPresentationDefinition to take jwt
* main: (37 commits)
  refactor test payload generation
  fix payload generation in test
  simplify test
  change test name to be more descriptive
  Revert "add version hipster badge and usage instructions to README"
  add version hipster badge and usage instructions to README
  add TODO
  version bump
  appease detekt
  account for signatures less than 64 bytes
  Fix null pointer in VC verify (#94)
  Do also authentication by default.
  Apply suggestions from code review
  bump version to 0.0.6
  updates
  Default ion creation sets assertion method (#93)
  Added more validation and tests
  Some fixes after testing
  Assertion method should be the default
  Better names
  ...
@codecov
Copy link

codecov bot commented Oct 27, 2023

Codecov Report

Merging #102 (b71e073) into main (934eb70) will increase coverage by 1.95%.
The diff coverage is 85.18%.

@@            Coverage Diff             @@
##             main     #102      +/-   ##
==========================================
+ Coverage   70.10%   72.06%   +1.95%     
==========================================
  Files          21       21              
  Lines        1201     1217      +16     
  Branches      137      140       +3     
==========================================
+ Hits          842      877      +35     
+ Misses        292      269      -23     
- Partials       67       71       +4     
Components Coverage Δ
credentials 75.00% <85.18%> (+7.87%) ⬆️
crypto 34.67% <ø> (ø)
dids 92.81% <ø> (ø)
common 60.83% <ø> (ø)

}
}
return satisfied
.forEach { inputDescriptorWithFields ->
Copy link
Contributor

@nitro-neal nitro-neal Oct 27, 2023

Choose a reason for hiding this comment

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

Does this cover the scenario:
if there are no filter and only a path?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it should via ln79 but will add a test :)

}
]
}
const val TBDEX_PD = """
Copy link
Contributor

Choose a reason for hiding this comment

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

Should add another test where there is no filter, only a path

Copy link
Contributor

@nitro-neal nitro-neal left a comment

Choose a reason for hiding this comment

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

Good job! I would say add a few more tests to make sure it works with the old test too basically ( a pd without a filter, just a path)

}

when {
field.filterSchema != null -> matchedFields.any {vcSatisfiesFieldFilterSchema(it, field.filterSchema!!)}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

matched field could be either an array or a single value.
if array, filterSchema needs to be applied to each item in the array. If any items satisfy the schema, return true
if single value, apply schema

Copy link
Contributor Author

Choose a reason for hiding this comment

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

matched field could also be an object

@@ -127,6 +127,7 @@ public class SubmissionRequirement(
/**
* Enumeration representing presentation rule options.
*/
// TODO this does not serialize correctly but sub reqs not supported right now
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't quite follow what this comment means. Would you mind elaborating? And perhaps also opening an issue?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Jackson does not know how to serialize/deserialize enum class Rules and enum class Optionality in a SubmissionRequirement, we probably need to write custom serializers/deserializers. However, the PEX impl throws an exception if SubmissionRequirement is present, so it doesn't seem worth writing the custom modules.

Want to have a convo with @decentralgabe around whether we should drop SubmissionRequirement from our data model entirely.

Can open an issue to track.

Copy link
Member

Choose a reason for hiding this comment

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

I'd just drop it for now - can add it back when/if needed

*/
public fun satisfiesPresentationDefinition(
credential: VerifiableCredential,
vcJwt: String,
Copy link
Contributor

Choose a reason for hiding this comment

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

Curious what was the motivation behind this change?

I worry that people may forget to verify the jwt, before doing anything with it. How do you propose we can handle that concern?

Copy link
Contributor

@nitro-neal nitro-neal Oct 27, 2023

Choose a reason for hiding this comment

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

I think its because ssome of the filter could be for the actual payload of the vc
$.iss is the correct way to filter by issuer not vc.issuer (this will be removed as per spec)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

agree w/ the concern, but it's better to decouple the logic IMO

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds like you're advocating for leaving as is. I remain cautious about the approach. Agree with the intent of decoupling verification logic from validation.

My proposal is to stick to the following convention:

  • When a function is dealing with data that's assumed to be trusted, use the VerifiableCredential type.
  • When a function is dealing with data that needs to be verified, use the secured representation (i.e. vcJwt or DI).

For this function, the data is assumed to be trusted already. Given that, it would fall to the first bucket.
On the other hand, the VerifiableCredential.verify function would follow the second pattern.

Alternatively, we could define types to represent:

  • A secured verifiable credential: JwVerifiableCredential and DataIntegrityVerifiableCredential.
  • An unsecured verifiable credential UnsecuredVerifiableCredential.

This would make it very difficult for users to screw up.

Either of these two would be more beneficial IMHO. Those are my suggestions, I'll leave it up to @phoebe-lew to decide whether they're useful or not.

*
* @param message The error message.
*/
public class PresentationExchangeError(message: String) : Error(message)
Copy link
Contributor

Choose a reason for hiding this comment

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

Couldn't find where error is defined, is it an exception?

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 is java.lang.Error, I'm actually not sure when to use error vs exception

Copy link
Contributor

Choose a reason for hiding this comment

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

From https://docs.oracle.com/javase%2F7%2Fdocs%2Fapi%2F%2F/java/lang/Error.html

An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch.

That sounds really scary 😱

In other PRs, we've tried to stick subclassing RuntimeException, like what's below https://github.com/TBD54566975/web5-kt/blob/02ea4b31a28cf68a4a3f9a9abc745e3273ceee79/dids/src/main/kotlin/web5/sdk/dids/DidIonManager.kt#L720

private val holderDid = DidKey.create(keyManager)
private val jsonMapper: ObjectMapper = ObjectMapper()
.registerKotlinModule()
.findAndRegisterModules()
Copy link
Contributor

Choose a reason for hiding this comment

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

Curious what this does?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually don't need this anymore! If we define custom serialization/deserialization modules, this tells the object mapper to pick those up. But managed to just use annotations to get the PD to serialize.

private val issuerDid = DidKey.create(keyManager)
private val holderDid = DidKey.create(keyManager)
private val jsonMapper: ObjectMapper = ObjectMapper()
.registerKotlinModule()
Copy link
Contributor

Choose a reason for hiding this comment

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

Curious what this does?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This one gets jackson's objectmapper to work nicely with kotlin

Copy link
Contributor

Choose a reason for hiding this comment

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

Interesting! First time i've seen this. Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

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

Personally, I think it's a better practice to commit the contents of TBDEX_PD into a separate file called tbdex_pd.json. Then you can load from disk and verify. This is advantageous because then we can start reusing test cases in other implementations.

A similar comment applies to VC_JWT.

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure, can do that

Copy link
Contributor

@andresuribe87 andresuribe87 left a comment

Choose a reason for hiding this comment

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

Awesome!

*/
public fun satisfiesPresentationDefinition(
credential: VerifiableCredential,
vcJwt: String,
Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds like you're advocating for leaving as is. I remain cautious about the approach. Agree with the intent of decoupling verification logic from validation.

My proposal is to stick to the following convention:

  • When a function is dealing with data that's assumed to be trusted, use the VerifiableCredential type.
  • When a function is dealing with data that needs to be verified, use the secured representation (i.e. vcJwt or DI).

For this function, the data is assumed to be trusted already. Given that, it would fall to the first bucket.
On the other hand, the VerifiableCredential.verify function would follow the second pattern.

Alternatively, we could define types to represent:

  • A secured verifiable credential: JwVerifiableCredential and DataIntegrityVerifiableCredential.
  • An unsecured verifiable credential UnsecuredVerifiableCredential.

This would make it very difficult for users to screw up.

Either of these two would be more beneficial IMHO. Those are my suggestions, I'll leave it up to @phoebe-lew to decide whether they're useful or not.

*
* @param message The error message.
*/
public class PresentationExchangeError(message: String) : Error(message)
Copy link
Contributor

Choose a reason for hiding this comment

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

From https://docs.oracle.com/javase%2F7%2Fdocs%2Fapi%2F%2F/java/lang/Error.html

An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch.

That sounds really scary 😱

In other PRs, we've tried to stick subclassing RuntimeException, like what's below https://github.com/TBD54566975/web5-kt/blob/02ea4b31a28cf68a4a3f9a9abc745e3273ceee79/dids/src/main/kotlin/web5/sdk/dids/DidIonManager.kt#L720

private val issuerDid = DidKey.create(keyManager)
private val holderDid = DidKey.create(keyManager)
private val jsonMapper: ObjectMapper = ObjectMapper()
.registerKotlinModule()
Copy link
Contributor

Choose a reason for hiding this comment

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

Interesting! First time i've seen this. Thanks!



private fun readPd(path: String): String {
return File(path).readText().trimIndent()
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
return File(path).readText().trimIndent()
return File(path).readText()

"eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJkaWQ6a2V5Ono2TWtrdU5tSmF0ZUNUZXI1V0JycUhCVUM0YUM3TjlOV1NyTURKNmVkQXY1V0NmMiIsInN1YiI6ImRpZDprZXk6ejZNa2t1Tm1KYXRlQ1RlcjVXQnJxSEJVQzRhQzdOOU5XU3JNREo2ZWRBdjVXQ2YyIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwiaWQiOiIxNjk4NDIyNDAxMzUyIiwidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsIlNhbmN0aW9uc0NyZWRlbnRpYWwiXSwiaXNzdWVyIjoiZGlkOmtleTp6Nk1ra3VObUphdGVDVGVyNVdCcnFIQlVDNGFDN045TldTck1ESjZlZEF2NVdDZjIiLCJpc3N1YW5jZURhdGUiOiIyMDIzLTEwLTI3VDE2OjAwOjAxWiIsImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmtleTp6Nk1ra3VObUphdGVDVGVyNVdCcnFIQlVDNGFDN045TldTck1ESjZlZEF2NVdDZjIiLCJiZWVwIjoiYm9vcCJ9fX0.Xhd9nDdkGarYFr6FP7wqsgj5CK3oGTfKU2LHNMvFIsvatgYlSucShDPI8uoeJ_G31uYPke-LJlRy-WVIhkudDg"


private fun readPd(path: String): String {
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
private fun readPd(path: String): String {
private fun readFile(path: String): String {

@phoebe-lew phoebe-lew merged commit a644e6f into main Oct 27, 2023
4 checks passed
@phoebe-lew phoebe-lew deleted the plew.update-pd-tests branch October 27, 2023 21:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants