-
Notifications
You must be signed in to change notification settings - Fork 3
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
feature/SDK-8 #27
feature/SDK-8 #27
Conversation
…to-extensions into feature/SDK-8
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.
See remarks
const query = `?${[offset && `page[after]=${offset}`, size && `page[size]=${size}`, controller && `controller=${controller}`] | ||
.filter(Boolean) | ||
.join('&')}` | ||
return await (await fetch(`https://api-pilot.ebsi.eu/did-registry/v5/identifiers${query}`)).json() |
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.
Please make sure that all the static links to EBSI are an optional parameter from a predefined set as well as string (string union). Then have a default value you can configure on the plugin for the EBSI environment. That way it will always use the default, and you can optionally provide a different env
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.
Added query url to getUrls method
*/ | ||
export const listDidDocuments = async (args: GetDidDocumentsParams): Promise<GetDidDocumentsResponse> => { | ||
const { offset, size, controller } = args | ||
const query = `?${[offset && `page[after]=${offset}`, size && `page[size]=${size}`, controller && `controller=${controller}`] |
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 is a really confusing construct to read, especially because of the string interpolation happening from the beginning. Please make that better readable
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.
Extracted it to if clauses
if (!did) { | ||
throw new Error('did parameter is required') | ||
} | ||
const query = `?${validAt && `valid_at=${validAt}`}` |
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.
Do not use string interpolation within string interpolation
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.
Extracted nested string interpolation into ternary
id: number | ||
}): Promise<Response> => { | ||
const { params, id } = args | ||
const options = { |
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.
Please extract these into a method. We now have the same things all over the place, with only a different method. If we need to change something in the future the chance of introducing bugs is high
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.
moved the code to the buildFetchOptions(...)
method
* @constant {string} jsonrpc | ||
*/ | ||
const jsonrpc = '2.0' // optional param of plugin? | ||
const baseUrl = 'https://api-pilot.ebsi.eu/did-registry/v5/jsonrpc' // optional param of plugin? |
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 should be part of a string union containing the different EBSI environments. Then we should concatenate the version and did-registry.
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.
Created EbsiEnvironment type which is a string intersection of different environments and moved it to src/types.ts
. Created a function getUrls
to build the url and moved it to src/function.ts
. Adjusted the service methods and the plugin constructor to receive an additional optional parameter: apiOpts
return SigningKey.computePublicKey(bytes, false) | ||
} | ||
case 'Secp256r1': { | ||
const jwk: JsonWebKey = toJwk(key.publicKeyHex, type, { use: JwkKeyUse.Signature, key }) |
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.
Why do we need to convert the public key hex to JWK and then back to public key hex?
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.
In other words, what is the difference? If there is one, please describe it
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.
The difference is explained in the documentation: "Public key as hex string. For an ES256K key, it must be in uncompressed format prefixed with "0x04". For other algorithms, it must be the JWK transformed to string and then to hex format."
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.
Please reread the implementation (which will be wrong anyway, as that is not how you convert a jwk to hex to begin with. We have functions for these conversions). The comment reads it should be hex and the last thing you do is convert to base16 which is hex.
As mentioned why would you need to do it to begin with? If the comment is correct then you already had the hex key, if not then you need to adjust, but converting a jwk to base16 directly always is wrong, you need to get the public key component first (and we have functions for these)
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.
Okay. It seems they really are doing a conversion on the JWK to hex, which is rather odd without a codec to begin with and thus prone to errors across platforms, but so be it. Please create a comment explaining what is happening and why, as I would immediately start working on this code if an error occurs, because it looks so of
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.
Added a comment explaining what and why is happening.
"debug": "^4.3.4", | ||
"did-resolver": "^4.1.0", | ||
"ethers": "^6.11.1", | ||
"jose": "^4.14.6", |
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.
Please merge other branch, because jose is still (or again?) listed as dependency and that for sure isn't compatible with RN
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.
Removed jose
dependency
…to-extensions into feature/SDK-8 # Conflicts: # packages/did-provider-ebsi/package.json # packages/did-provider-ebsi/src/EbsiDidProvider.ts # packages/did-provider-ebsi/src/types.ts # pnpm-lock.yaml
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.
Please see remarks
@@ -53,6 +94,125 @@ export class EbsiDidProvider extends AbstractIdentifierProvider { | |||
throw Error(`Type ${type} not supported`) | |||
} | |||
|
|||
async createEbsiDid( | |||
args: { |
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.
Please create an interface/type out of this like done elsewhere
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.
extracted CreateEbsiDidParams interface
async createEbsiDid( | ||
args: { | ||
identifier: Omit<IIdentifier, 'provider'> | ||
secp256k1ManagedKeyInfo: ManagedKeyInfo |
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.
What is the reason we expect ManagedKeyInfos instead of kids for these? This is a public function and in most situations we would use a kid for them
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.
Moved it to functions.ts as part of another comment
) | ||
} | ||
|
||
private sendTransaction = async (args: { docTransactionResponse: Response; kid: string; id: number; apiOpts?: ApiOpts }, context: IContext) => { |
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.
Can we move a lot of these methods to functions elsewhere. They are now all in the Ebsi DID provider, which is following the Veramo contract. A lot of these methods are stateless and thus could become external functions, so they are reusable also outside the provider
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.
Moved the Veramo unrelated methods to functions.ts
args: { | ||
did: string | ||
document: Partial<DIDDocument> | ||
options?: { [p: string]: any } | ||
}, | ||
context: IAgentContext<IKeyManager> | ||
// TODO extract a type |
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.
Please create the type. The TODO was more work than creating the type itself
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.
Extracted interface UpdateIdentifierParams
@@ -117,14 +277,31 @@ export class EbsiDidProvider extends AbstractIdentifierProvider { | |||
throw Error(`Not (yet) implemented for the EBSI did provider`) | |||
} | |||
|
|||
updateIdentifier( | |||
// TODO How does it work? Not inferable from the api: https://hub.ebsi.eu/apis/pilot/did-registry/v5/post-jsonrpc#updatebasedocument |
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.
What do you mean with not inferable? Of course I know what the did is. Also this is an optional method to implement once you want to work with passing in updated (partial) did documents. The regular way would be the add/remove service endpoint and add/remove keys methods
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.
What will actually change in the did? That's the request body:
{
"jsonrpc": "2.0",
"method": "updateBaseDocument",
"params": [
{
"from": "0xc9765eC58E49e6E386549CEAA34FB0d8bB69C320",
"did": "did:ebsi:z23eve8qDNzYuNVqfSaErpuJ",
"baseDocument": "{\"@context\":[\"https://www.w3.org/ns/did/v1\",\"https://w3id.org/security/suites/jws-2020/v1\"]}"
}
],
"id": 524
}
And there is no did document.
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.
Thenit is likely this method should not have been implemented to begin with and throw an error instead. Veramo uses add and delete services and keys methods to manage updates to the identifier and did document. It recently added a method to pass in a new (partial) did document. If however a did provider cannot work with that it should throw an error.
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.
Just throwing an error then
const { key, type } = args | ||
switch (type) { | ||
case 'Secp256k1': { | ||
const bytes = getBytes('0x' + key.publicKeyHex, 'key') |
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.
Did you check whether we are not already storing the key in uncompressed form?
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.
yes, our keys are 66 bytes long and start with 02 or 03. We are looking for a key that is 130 bytes long and start with 04
return SigningKey.computePublicKey(bytes, false) | ||
} | ||
case 'Secp256r1': { | ||
const jwk: JsonWebKey = toJwk(key.publicKeyHex, type, { use: JwkKeyUse.Signature, key }) |
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.
Okay. It seems they really are doing a conversion on the JWK to hex, which is rather odd without a codec to begin with and thus prone to errors across platforms, but so be it. Please create a comment explaining what is happening and why, as I would immediately start working on this code if an error occurs, because it looks so of
return base64url(sha256(data)) | ||
} | ||
|
||
const check = (value: unknown, description: 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.
Please make the name more descriptive like assertPresent.
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.
renamed it to checkPresent
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.
huh, checkPresent leaves the reader to guess whether it is returning booleans, doing some other logic or doing assertions. Why would you go with a less optimal name than suggested? The suggestion made really clear that the method would be throwing errors
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.
renamed to assert present
token: string | ||
apiOpts?: ApiOpts | ||
}): Promise<Response> => { | ||
const { params, id, token, apiOpts } = args |
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.
Still the same comment as I made earlier about the method being different. We now have 4 or 5 times 3 lines which litteraly are the same except for the method value being different. Please create one single method and call that with the params, as this can only lead to bugs in th efuture
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.
Refactored it to a single function callRpcMethod
"@sphereon/ssi-sdk-ext.did-resolver-ebsi": "workspace:*", | ||
"@sphereon/ssi-sdk-ext.did-resolver-ebsi": "workspace:^", | ||
"@sphereon/ssi-sdk-ext.key-utils": "workspace:^", | ||
"@transmute/did-key-bls12381": "0.3.0-unstable.10", |
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.
Why is this dep added?
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.
Not used anywhere, removed
…hrowing exception
No description provided.