From efde15eae54340cdbcf0d94b274b22df4558608f Mon Sep 17 00:00:00 2001 From: Carlos Rincon <“carlos.r@affinidi.com”> Date: Tue, 28 Jan 2025 22:42:28 +0100 Subject: [PATCH 1/4] qa: integration tests --- tests/integration/dart/pubspec.yaml | 7 + .../dart/test/auth_provider_test.dart | 1 + .../test/consumer_auth_provider_test.dart | 1 + .../test/credential_issuance_client_test.dart | 60 +++++---- .../test/vault_data_manager_client_test.dart | 122 ++++++++++++++++-- .../dart/test/verification_client_test.dart | 83 ++++++++++++ .../dart/test/wallets_client_test.dart | 4 +- 7 files changed, 242 insertions(+), 36 deletions(-) create mode 100644 tests/integration/dart/test/verification_client_test.dart diff --git a/tests/integration/dart/pubspec.yaml b/tests/integration/dart/pubspec.yaml index b235a1655..cae786c0c 100644 --- a/tests/integration/dart/pubspec.yaml +++ b/tests/integration/dart/pubspec.yaml @@ -15,11 +15,18 @@ dev_dependencies: path: ../../../clients/dart/credential_issuance_client affinidi_tdk_vault_data_manager_client: path: ../../../clients/dart/vault_data_manager_client + affinidi_tdk_credential_verification_client: + # path: ../../../clients/dart/credential_verification_client + path: ../../../../openapi-sdk-generator/.github/affinidi-tdk/clients/dart/credential_verification_client + affinidi_tdk_cryptography: ^1.0.0 + vault_file_system_encryption_service: + path: ../../../../tdk-dart-bussiness-layer/packages/vault_file_system_encryption_service dotenv: ^4.2.0 lints: ^5.0.0 test: ^1.24.0 pointycastle: ^3.9.1 dart_jsonwebtoken: ^2.12.0 built_collection: ^5.1.1 + built_value: ^8.9.3 dio: '^5.2.0' one_of: ^1.5.0 \ No newline at end of file diff --git a/tests/integration/dart/test/auth_provider_test.dart b/tests/integration/dart/test/auth_provider_test.dart index 5ec0a7d06..862a1cd08 100644 --- a/tests/integration/dart/test/auth_provider_test.dart +++ b/tests/integration/dart/test/auth_provider_test.dart @@ -1,5 +1,6 @@ import 'package:test/test.dart'; import 'package:affinidi_tdk_auth_provider/affinidi_tdk_auth_provider.dart'; + import 'environment.dart'; void main() { diff --git a/tests/integration/dart/test/consumer_auth_provider_test.dart b/tests/integration/dart/test/consumer_auth_provider_test.dart index 881cca5d0..e67e12ab8 100644 --- a/tests/integration/dart/test/consumer_auth_provider_test.dart +++ b/tests/integration/dart/test/consumer_auth_provider_test.dart @@ -1,5 +1,6 @@ import 'package:test/test.dart'; import 'package:affinidi_tdk_consumer_auth_provider/affinidi_tdk_consumer_auth_provider.dart'; + import 'environment.dart'; void main() { diff --git a/tests/integration/dart/test/credential_issuance_client_test.dart b/tests/integration/dart/test/credential_issuance_client_test.dart index 35703b5f0..597b36787 100644 --- a/tests/integration/dart/test/credential_issuance_client_test.dart +++ b/tests/integration/dart/test/credential_issuance_client_test.dart @@ -1,10 +1,11 @@ import 'package:dio/dio.dart'; import 'package:test/test.dart'; import 'package:one_of/one_of.dart'; -// import 'package:built_collection/built_collection.dart'; +import 'package:built_collection/built_collection.dart'; import 'package:affinidi_tdk_auth_provider/affinidi_tdk_auth_provider.dart'; import 'package:affinidi_tdk_credential_issuance_client/affinidi_tdk_credential_issuance_client.dart'; import 'package:affinidi_tdk_wallets_client/affinidi_tdk_wallets_client.dart'; + import 'environment.dart'; void main() { @@ -24,17 +25,22 @@ void main() { ); // issuance client - final dio = Dio(BaseOptions( - baseUrl: AffinidiTdkCredentialIssuanceClient.basePath, - connectTimeout: const Duration(seconds: 5), - receiveTimeout: const Duration(seconds: 5), - )); final issuanceClient = AffinidiTdkCredentialIssuanceClient( - dio: dio, authTokenHook: authProvider.fetchProjectScopedToken); + dio: Dio(BaseOptions( + baseUrl: AffinidiTdkCredentialIssuanceClient.basePath, + connectTimeout: const Duration(seconds: 5), + receiveTimeout: const Duration(seconds: 5), + )), + authTokenHook: authProvider.fetchProjectScopedToken); configurationApi = issuanceClient.getConfigurationApi(); // wallet client final walletClient = AffinidiTdkWalletsClient( + dio: Dio(BaseOptions( + baseUrl: AffinidiTdkWalletsClient.basePath, + connectTimeout: const Duration(seconds: 5), + receiveTimeout: const Duration(seconds: 5), + )), authTokenHook: authProvider.fetchProjectScopedToken); walletApi = walletClient.getWalletApi(); @@ -69,25 +75,31 @@ void main() { final description = 'Test issuance config'; final format = CreateIssuanceConfigInputFormatEnum.ldpVc; final credentialOfferDuration = 600; - // final credentialSupported = [ - // CredentialSupportedObject((b) => b - // ..credentialTypeId = 'TDriversLicenseV1R1' - // ..jsonSchemaUrl = - // 'https://schema.affinidi.io/TDriversLicenseV1R1.jsonld' - // ..jsonLdContextUrl = - // 'https://schema.affinidi.io/TDriversLicenseV1R1.json') - // ]; + final credentialSupported = [ + CredentialSupportedObject((b) => b + ..credentialTypeId = 'TDriversLicenseV1R1' + ..jsonSchemaUrl = + 'https://schema.affinidi.io/TDriversLicenseV1R1.json' + ..jsonLdContextUrl = + 'https://schema.affinidi.io/TDriversLicenseV1R1.jsonld' + ..metadata = (SupportedCredentialMetadataBuilder() + ..display = ListBuilder([ + SupportedCredentialMetadataDisplayInner((b) => b + ..name = 'Test Display' + ..logo = (SupportedCredentialMetadataItemLogoBuilder() + ..url = 'https://example.com/logo.png' + ..altText = 'Logo')) + ]))) + ]; // create config final configInputBuilder = CreateIssuanceConfigInputBuilder() - ..issuerWalletId = walletId - ..name = name - ..description = description - ..format = format - ..credentialOfferDuration = credentialOfferDuration - // ..credentialSupported = ListBuilder(credentialSupported) - // - ; + ..issuerWalletId = walletId + ..name = name + ..description = description + ..format = format + ..credentialOfferDuration = credentialOfferDuration + ..credentialSupported = ListBuilder(credentialSupported); final createdConfig = (await configurationApi.createIssuanceConfig( createIssuanceConfigInput: configInputBuilder.build())) .data; @@ -108,7 +120,7 @@ void main() { equals(credentialOfferDuration)); expect(configDetails.issuerUri, isNotEmpty); expect(configDetails.issuerDid, isNotEmpty); - // expect(configDetails.credentialSupported, equals(credentialSupported)); + expect(configDetails.credentialSupported, equals(credentialSupported)); // list config var configs = diff --git a/tests/integration/dart/test/vault_data_manager_client_test.dart b/tests/integration/dart/test/vault_data_manager_client_test.dart index c0f9f2ffc..8cfa05438 100644 --- a/tests/integration/dart/test/vault_data_manager_client_test.dart +++ b/tests/integration/dart/test/vault_data_manager_client_test.dart @@ -1,14 +1,32 @@ -import 'package:affinidi_tdk_consumer_auth_provider/affinidi_tdk_consumer_auth_provider.dart'; +import 'dart:convert'; + +import 'package:dio/dio.dart'; import 'package:test/test.dart'; +import 'package:affinidi_tdk_consumer_auth_provider/affinidi_tdk_consumer_auth_provider.dart'; import 'package:affinidi_tdk_vault_data_manager_client/affinidi_tdk_vault_data_manager_client.dart'; +import 'package:affinidi_tdk_cryptography/affinidi_tdk_cryptography.dart'; +import 'package:vault_file_system_encryption_service/vault_file_system_encryption_service.dart'; + import 'environment.dart'; +const rootNodeIdBase64Encoded = 'NzY3ZjY='; +const vfsSalt = + '031b96f9b4641f508702c03b5643fd5de8d90465fdb0bdf6abe5d6c1c8a667a8'; + +Future> getVaultFileSystemPublicKey() async { + final Dio dio = Dio(); + final absoluteUrl = + "${AffinidiTdkVaultDataManagerClient.basePath}/.well-known/jwks.json"; + final response = await dio.get(absoluteUrl); + final jwks = (response.data['keys'] as List).first; + return jwks; +} + void main() { group('Vault Data Manager Client Integration Tests', () { - // late ConfigApi configApi; - // late FilesApi filesApi; late NodesApi nodesApi; - // late ProfileDataApi profileDataApi; + late Map vfsPublicKey; + late VaultFileSystemEncryptionService vaultFileSystemEncryptionService; setUp(() async { final env = getVaultEnvironment(); @@ -19,16 +37,98 @@ void main() { final apiClient = AffinidiTdkVaultDataManagerClient( authTokenHook: consumerAuthProvider.fetchConsumerToken, ); - - // configApi = apiClient.getConfigApi(); - // filesApi = apiClient.getFilesApi(); nodesApi = apiClient.getNodesApi(); - // profileDataApi = apiClient.getProfileDataApi(); + + vfsPublicKey = await getVaultFileSystemPublicKey(); + vaultFileSystemEncryptionService = VaultFileSystemEncryptionService( + cryptographyService: CryptographyService(), + jwk: vfsPublicKey, + encryptedSeed: env.encryptedSeed, + walletPassword: env.encryptionKey, + vfsNonce: utf8.encode(vfsSalt), + ); }); - test('list root node children', () async { - final children = (await nodesApi.listRootNodeChildren()).data; - print(children); + test('CRUDL Root Nodes', () async { + // get list of profiles + var initialProfiles = (await nodesApi.listRootNodeChildren()).data; + expect(initialProfiles, isNotNull); + expect(initialProfiles!.nodes, isNotNull); + + // add a new profile + final dekGenerateModel = + await vaultFileSystemEncryptionService.generateDek(); + final edekInfoBuilder = EdekInfoBuilder() + ..edek = + base64.encode(dekGenerateModel.dekEncryptedByWalletCryptoMaterial) + ..dekekId = dekGenerateModel.walletCryptoMaterialHash; + final createNodeInputBuilder = CreateNodeInputBuilder() + ..name = 'Test Node' + ..type = NodeType.PROFILE + ..parentNodeId = rootNodeIdBase64Encoded + ..edekInfo = edekInfoBuilder + ..dek = base64.encode(dekGenerateModel.dekEncryptedByVfsPublicKey); + final newProfile = (await nodesApi.createNode( + createNodeInput: createNodeInputBuilder.build())) + .data; + expect(newProfile, isNotNull); + expect(newProfile!.nodeId, isNotNull); + + // get details of new profile + final nodeDetails = + (await nodesApi.getDetailedNodeInfo(nodeId: newProfile.nodeId)).data; + expect(nodeDetails, isNotNull); + expect(nodeDetails!.nodeId, equals(newProfile.nodeId)); + expect(nodeDetails.name, equals(createNodeInputBuilder.name)); + expect(nodeDetails.type, equals(createNodeInputBuilder.type)); + expect(nodeDetails.parentNodeId, + equals(createNodeInputBuilder.parentNodeId)); + expect(nodeDetails.edekInfo, isNotNull); + expect(nodeDetails.edekInfo!.edek, equals(edekInfoBuilder.edek)); + + // update profile + final updateNodeInput = UpdateNodeInputBuilder() + ..name = 'Updated Test Node' + ..description = 'Updated description' + ..metadata = jsonEncode({ + 'pictureURI': 'https://example.com/picture.jpg', + }); + final updatedProfile = (await nodesApi.updateNode( + nodeId: newProfile.nodeId, + updateNodeInput: updateNodeInput.build())) + .data; + expect(updatedProfile, isNotNull); + expect(updatedProfile!.nodeId, equals(newProfile.nodeId)); + expect(updatedProfile.name, equals(updateNodeInput.name)); + expect(updatedProfile.description, equals(updateNodeInput.description)); + expect(updatedProfile.metadata, equals(updateNodeInput.metadata)); + + // get updated list of profiles + var updatedProfiles = (await nodesApi.listRootNodeChildren()).data; + expect(updatedProfiles, isNotNull); + expect(updatedProfiles!.nodes, isNotNull); + expect(updatedProfiles.nodes!.length, + equals(initialProfiles.nodes!.length + 1)); + final updatedProfileFromList = updatedProfiles.nodes! + .firstWhere((node) => node.nodeId == newProfile.nodeId); + expect(updatedProfileFromList, isNotNull); + expect(updatedProfileFromList.nodeId, equals(newProfile.nodeId)); + expect(updatedProfileFromList.name, equals(updateNodeInput.name)); + expect(updatedProfileFromList.description, + equals(updateNodeInput.description)); + expect(updatedProfileFromList.metadata, equals(updateNodeInput.metadata)); + + // delete profile + await nodesApi.deleteNode(nodeId: newProfile.nodeId); + updatedProfiles = (await nodesApi.listRootNodeChildren()).data; + expect(updatedProfiles, isNotNull); + expect(updatedProfiles!.nodes, isNotNull); + expect( + updatedProfiles.nodes!.length, equals(initialProfiles.nodes!.length)); + expect( + updatedProfiles.nodes! + .any((node) => node.nodeId == newProfile.nodeId), + isFalse); }); }); } diff --git a/tests/integration/dart/test/verification_client_test.dart b/tests/integration/dart/test/verification_client_test.dart new file mode 100644 index 000000000..59d4520db --- /dev/null +++ b/tests/integration/dart/test/verification_client_test.dart @@ -0,0 +1,83 @@ +import 'package:built_value/json_object.dart'; +import 'package:dio/dio.dart'; +import 'package:one_of/one_of.dart'; +import 'package:test/test.dart'; +import 'package:built_collection/built_collection.dart'; +import 'package:affinidi_tdk_auth_provider/affinidi_tdk_auth_provider.dart'; +import 'package:affinidi_tdk_credential_verification_client/affinidi_tdk_credential_verification_client.dart'; + +import 'environment.dart'; + +void main() { + group('Credential Verification Client Integration Tests', () { + late DefaultApi verificationApi; + + setUp(() async { + final env = getProjectEnvironment(); + final authProvider = AuthProvider( + projectId: env.projectId, + tokenId: env.tokenId, + privateKey: env.privateKey, + keyId: env.keyId, + passphrase: env.passphrase, + ); + final dio = Dio(BaseOptions( + baseUrl: AffinidiTdkCredentialVerificationClient.basePath, + connectTimeout: const Duration(seconds: 5), + receiveTimeout: const Duration(seconds: 5), + )); + final apiClient = AffinidiTdkCredentialVerificationClient( + dio: dio, authTokenHook: authProvider.fetchProjectScopedToken); + verificationApi = apiClient.getDefaultApi(); + }); + + test('Verify VC', () async { + final w3Context = W3cCredentialContextInnerBuilder() + ..oneOf = OneOf2, String>( + value: 'https://www.w3.org/2018/credentials/v1', typeIndex: 1); + final schemaContext = W3cCredentialContextInnerBuilder() + ..oneOf = OneOf2, String>( + value: 'https://schema.affinidi.com/EmailV1-0.jsonld', + typeIndex: 1); + final credentialBuilder = W3cCredentialBuilder() + ..atContext = ListBuilder([w3Context.build(), schemaContext.build()]) + ..id = 'claimId:63b5d11c0d1b5566' + ..type = ListBuilder(['VerifiableCredential', 'Email']) + ..holder = (W3cCredentialHolderBuilder() + ..oneOf = OneOf2( + value: JsonObject({ + 'id': + 'did:key:zQ3shiEH16wHAfbQSSuYB1Lc3KSQC31W4gkaXKa8PgCSz83du' + }), + typeIndex: 0)) + ..credentialSubject = (W3cCredentialCredentialSubjectBuilder() + ..oneOf = OneOf2, JsonObject>( + value: + JsonObject({'email': 'non-existant-email@non-existant.com'}), + typeIndex: 1)) + ..credentialSchema = (W3cCredentialCredentialSchemaBuilder() + ..id = 'https://schema.affinidi.com/EmailV1-0.json' + ..type = 'JsonSchemaValidator2018') + ..issuanceDate = '2024-05-30T19:14:31.964Z' + ..expirationDate = '2025-05-30T19:14:31.964Z' + ..issuer = 'did:key:zQ3shiEH16wHAfbQSSuYB1Lc3KSQC31W4gkaXKa8PgCSz83du' + ..proof = (W3cProofBuilder() + ..type = 'EcdsaSecp256k1Signature2019' + ..created = '2024-05-30T19:14:31Z' + ..verificationMethod = + 'did:key:zQ3shiEH16wHAfbQSSuYB1Lc3KSQC31W4gkaXKa8PgCSz83du#zQ3shiEH16wHAfbQSSuYB1Lc3KSQC31W4gkaXKa8PgCSz83du' + ..proofPurpose = 'assertionMethod' + ..jws = + 'eyJhbGciOiJFUzI1NksiLCJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdfQ..FEqEKSPZCHKY9XuCywtOSBzhn1EHRFEle67bfJt-3wUFvMnk9pGmQO52EOCB65WcgXSesCgKasgXZKZOJXbF5A'); + final credential = credentialBuilder.build(); + final verifyCredentialInputBuilder = VerifyCredentialInputBuilder() + ..verifiableCredentials = ListBuilder([credential]); + final verificationResponse = (await verificationApi.verifyCredentials( + verifyCredentialInput: verifyCredentialInputBuilder.build())) + .data; + expect(verificationResponse, isNotNull); + expect(verificationResponse!.isValid, isTrue); + expect(verificationResponse.errors, isEmpty); + }); + }); +} diff --git a/tests/integration/dart/test/wallets_client_test.dart b/tests/integration/dart/test/wallets_client_test.dart index 72a2e3d95..d7a3d5cb5 100644 --- a/tests/integration/dart/test/wallets_client_test.dart +++ b/tests/integration/dart/test/wallets_client_test.dart @@ -3,6 +3,7 @@ import 'package:one_of/one_of.dart'; import 'package:test/test.dart'; import 'package:affinidi_tdk_auth_provider/affinidi_tdk_auth_provider.dart'; import 'package:affinidi_tdk_wallets_client/affinidi_tdk_wallets_client.dart'; + import 'environment.dart'; void main() { @@ -41,7 +42,6 @@ void main() { final createdWallet = (await walletApi.createWallet( createWalletInput: walletInputBuilder.build())) .data; - print(createdWallet); expect(createdWallet, isNotNull); expect(createdWallet!.wallet, isNotNull); expect(createdWallet.wallet!.id, isNotEmpty); @@ -53,6 +53,8 @@ void main() { expect(createdWallet.wallet!.keys!.length, greaterThan(0)); expect(createdWallet.wallet!.keys!.first.id, isNotEmpty); expect(createdWallet.wallet!.keys!.first.ari, isNotEmpty); + + await walletApi.deleteWallet(walletId: createdWallet.wallet!.id!); }); }); } From 552e49be3954b96c2a73b38cff27f672c7e12f69 Mon Sep 17 00:00:00 2001 From: Carlos Rincon <“carlos.r@affinidi.com”> Date: Thu, 20 Feb 2025 11:22:43 +0100 Subject: [PATCH 2/4] chore: test signed commits --- tests/integration/dart/test/verification_client_test.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/integration/dart/test/verification_client_test.dart b/tests/integration/dart/test/verification_client_test.dart index 59d4520db..32ed425fa 100644 --- a/tests/integration/dart/test/verification_client_test.dart +++ b/tests/integration/dart/test/verification_client_test.dart @@ -21,13 +21,12 @@ void main() { keyId: env.keyId, passphrase: env.passphrase, ); - final dio = Dio(BaseOptions( + final apiClient = AffinidiTdkCredentialVerificationClient( + dio: Dio(BaseOptions( baseUrl: AffinidiTdkCredentialVerificationClient.basePath, connectTimeout: const Duration(seconds: 5), receiveTimeout: const Duration(seconds: 5), - )); - final apiClient = AffinidiTdkCredentialVerificationClient( - dio: dio, authTokenHook: authProvider.fetchProjectScopedToken); + )), authTokenHook: authProvider.fetchProjectScopedToken); verificationApi = apiClient.getDefaultApi(); }); From be0f643118bdd379c544aec5b83fd8a6c8fc167f Mon Sep 17 00:00:00 2001 From: Carlos Rincon <“carlos.r@affinidi.com”> Date: Thu, 20 Feb 2025 11:39:04 +0100 Subject: [PATCH 3/4] chore: attempt commit signature --- tests/integration/dart/test/verification_client_test.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration/dart/test/verification_client_test.dart b/tests/integration/dart/test/verification_client_test.dart index 32ed425fa..a7da10d8e 100644 --- a/tests/integration/dart/test/verification_client_test.dart +++ b/tests/integration/dart/test/verification_client_test.dart @@ -21,6 +21,7 @@ void main() { keyId: env.keyId, passphrase: env.passphrase, ); + final apiClient = AffinidiTdkCredentialVerificationClient( dio: Dio(BaseOptions( baseUrl: AffinidiTdkCredentialVerificationClient.basePath, From 0b537d58ab1fffa60fbcfe589773a411c54a9107 Mon Sep 17 00:00:00 2001 From: Carlos Rincon Date: Thu, 20 Feb 2025 11:41:09 +0100 Subject: [PATCH 4/4] chore: attempt commit signature --- tests/integration/dart/test/verification_client_test.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/integration/dart/test/verification_client_test.dart b/tests/integration/dart/test/verification_client_test.dart index a7da10d8e..32ed425fa 100644 --- a/tests/integration/dart/test/verification_client_test.dart +++ b/tests/integration/dart/test/verification_client_test.dart @@ -21,7 +21,6 @@ void main() { keyId: env.keyId, passphrase: env.passphrase, ); - final apiClient = AffinidiTdkCredentialVerificationClient( dio: Dio(BaseOptions( baseUrl: AffinidiTdkCredentialVerificationClient.basePath,