-
Notifications
You must be signed in to change notification settings - Fork 10
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
Conversation
- 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 Report
@@ 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
|
} | ||
} | ||
return satisfied | ||
.forEach { inputDescriptorWithFields -> |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 = """ |
There was a problem hiding this comment.
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
There was a problem hiding this 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!!)} |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
andDataIntegrityVerifiableCredential
. - 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) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious what this does?
There was a problem hiding this comment.
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() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious what this does?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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!
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sure, can do that
There was a problem hiding this 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, |
There was a problem hiding this comment.
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
andDataIntegrityVerifiableCredential
. - 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) |
There was a problem hiding this comment.
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() |
There was a problem hiding this comment.
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() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return File(path).readText().trimIndent() | |
return File(path).readText() |
"eyJhbGciOiJFZERTQSJ9.eyJpc3MiOiJkaWQ6a2V5Ono2TWtrdU5tSmF0ZUNUZXI1V0JycUhCVUM0YUM3TjlOV1NyTURKNmVkQXY1V0NmMiIsInN1YiI6ImRpZDprZXk6ejZNa2t1Tm1KYXRlQ1RlcjVXQnJxSEJVQzRhQzdOOU5XU3JNREo2ZWRBdjVXQ2YyIiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwiaWQiOiIxNjk4NDIyNDAxMzUyIiwidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsIlNhbmN0aW9uc0NyZWRlbnRpYWwiXSwiaXNzdWVyIjoiZGlkOmtleTp6Nk1ra3VObUphdGVDVGVyNVdCcnFIQlVDNGFDN045TldTck1ESjZlZEF2NVdDZjIiLCJpc3N1YW5jZURhdGUiOiIyMDIzLTEwLTI3VDE2OjAwOjAxWiIsImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmtleTp6Nk1ra3VObUphdGVDVGVyNVdCcnFIQlVDNGFDN045TldTck1ESjZlZEF2NVdDZjIiLCJiZWVwIjoiYm9vcCJ9fX0.Xhd9nDdkGarYFr6FP7wqsgj5CK3oGTfKU2LHNMvFIsvatgYlSucShDPI8uoeJ_G31uYPke-LJlRy-WVIhkudDg" | ||
|
||
|
||
private fun readPd(path: String): String { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private fun readPd(path: String): String { | |
private fun readFile(path: String): String { |
No description provided.