From fe9c5822af814ab6bbc2a33a43a63353c08db540 Mon Sep 17 00:00:00 2001 From: Alberto L Date: Mon, 6 Jul 2026 12:04:48 -0600 Subject: [PATCH 01/12] feat: Phase 3 app layer - RN 0.81.5, React 19.1, bifold 3.0.16, credo 0.6.3 Wire the app workspace to the upgraded bifold 3.x submodule: - deps: react-native 0.81.5 / react 19.1.0, @bifold/* 3.0.16 portals (incl. new @bifold/react-hooks), @credo-ts/* 0.6.3 with @credo-ts/didcomm, askar -> @openwallet-foundation/askar-react-native 0.6.0, expo modules, reanimated + keyboard-controller; adopt upstream patch set, drop 0.5.17 patches; remove Storybook entirely - bc-agent-modules: credo 0.6 module graph (DidCommModule config, KMS with askar + expo secure-environment, explicit JSON-LD/AnonCreds DIDComm format services, VRC document loader) - useBCAgentSetup: wallet id/key move into AskarModule store config (no agent.wallet.open()), didcomm transport registration, guarded indy-vdr pool warm-up - attestation: remove DRPC-based BC attestation flow (@credo-ts/drpc has no stable 0.6.x and Keyring does not use BC's attestation service); delete utils/drpc.ts; keep bifold AttestationMonitor interface - credo 0.6 API renames across hooks/utils (DidComm* types, proofExchangeRecordId, metadata keys from @credo-ts/anoncreds root) - jest/babel: sync transformIgnorePatterns with bifold core, map @bifold/* to sources, RN 0.81 Keyboard/BackHandler/reanimated mocks, drop module-resolver root '.' (rewrote node_modules '.' imports to app index.js), add export-namespace-from + reanimated babel plugins - snapshots updated for RN 0.81 style flattening; theme gains new bifold 3.x IBrandColors fields App gate (JS): typecheck 0 errors, eslint clean, jest 14 suites / 27 tests pass. Native Android/iOS project upgrade is the next step. --- ...ure-environment-npm-0.1.5-3c2a8f1b94.patch | 18 + ...o-ts-anoncreds-npm-0.5.17-9f101d8e96.patch | 40 - ...@credo-ts-core-npm-0.5.17-c528a69dd8.patch | 24 - ...do-ts-indy-vdr-npm-0.5.17-aa0b05041f.patch | 13 - ...-0.6.3-secure-environment-biometrics.patch | 68 + ...ds-react-native-npm-0.2.4-644cafe308.patch | 21 - ...ar-react-native-npm-0.2.3-3207b51eab.patch | 21 - ...dr-react-native-npm-0.2.2-627d424b96.patch | 194 - ...dr-react-native-npm-0.2.4-d7ed0b15da.patch | 22 + ...indy-vdr-shared-npm-0.2.2-b989282fc6.patch | 16 - UPGRADE_PROGRESS.md | 65 +- app/AppStorybook.tsx | 18 - .../{@credo-ts => @bifold}/react-hooks.ts | 6 +- .../__snapshots__/EmptyList.test.tsx.snap | 40 +- .../__snapshots__/QRCodeFlow.test.tsx.snap | 81 +- .../__snapshots__/TabNavigation.test.tsx.snap | 81 +- .../__snapshots__/Developer.test.tsx.snap | 33 +- .../PersonCredential.test.tsx.snap | 40 +- .../RemoteLogWarning.test.tsx.snap | 49 +- app/__tests__/utils/periodicPickup.test.ts | 27 +- app/babel.config.js | 10 +- app/jest.config.js | 23 +- app/jestSetup.js | 53 +- app/package.json | 138 +- app/src/hooks/notifications.ts | 36 +- app/src/hooks/useBCAgentSetup.ts | 52 +- .../components/AddCredentialSlider.tsx | 10 +- .../components/HomeHeaderView.tsx | 2 +- .../person-flow/screens/PersonCredential.tsx | 2 +- .../screens/PersonCredentialLoading.tsx | 10 +- .../features/person-flow/utils/BCIDHelper.ts | 4 +- app/src/keyring-theme/theme.ts | 7 + app/src/screens/Developer.tsx | 8 +- app/src/services/attestation.ts | 378 +- app/src/utils/PushNotificationsHelper.ts | 11 +- app/src/utils/bc-agent-modules.ts | 184 +- app/src/utils/credentials.ts | 14 +- app/src/utils/drpc.ts | 68 - app/src/utils/mediator.ts | 9 +- app/storybook/addons.ts | 4 - app/storybook/index.ts | 28 - app/storybook/rn-addons.ts | 3 - .../stories/Brandings/Brandings.stories.tsx | 295 - .../stories/Button/Button.stories.tsx | 46 - app/storybook/stories/CenterView/index.tsx | 17 - app/storybook/stories/index.ts | 2 - bifold | 2 +- package.json | 25 +- yarn.lock | 16166 ++++------------ 49 files changed, 4743 insertions(+), 13741 deletions(-) create mode 100644 .yarn/patches/@animo-id-expo-secure-environment-npm-0.1.5-3c2a8f1b94.patch delete mode 100644 .yarn/patches/@credo-ts-anoncreds-npm-0.5.17-9f101d8e96.patch delete mode 100644 .yarn/patches/@credo-ts-core-npm-0.5.17-c528a69dd8.patch delete mode 100644 .yarn/patches/@credo-ts-indy-vdr-npm-0.5.17-aa0b05041f.patch create mode 100644 .yarn/patches/@credo-ts-react-native-npm-0.6.3-secure-environment-biometrics.patch delete mode 100644 .yarn/patches/@hyperledger-anoncreds-react-native-npm-0.2.4-644cafe308.patch delete mode 100644 .yarn/patches/@hyperledger-aries-askar-react-native-npm-0.2.3-3207b51eab.patch delete mode 100644 .yarn/patches/@hyperledger-indy-vdr-react-native-npm-0.2.2-627d424b96.patch create mode 100644 .yarn/patches/@hyperledger-indy-vdr-react-native-npm-0.2.4-d7ed0b15da.patch delete mode 100644 .yarn/patches/@hyperledger-indy-vdr-shared-npm-0.2.2-b989282fc6.patch delete mode 100644 app/AppStorybook.tsx rename app/__mocks__/{@credo-ts => @bifold}/react-hooks.ts (87%) delete mode 100644 app/src/utils/drpc.ts delete mode 100644 app/storybook/addons.ts delete mode 100644 app/storybook/index.ts delete mode 100644 app/storybook/rn-addons.ts delete mode 100644 app/storybook/stories/Brandings/Brandings.stories.tsx delete mode 100644 app/storybook/stories/Button/Button.stories.tsx delete mode 100644 app/storybook/stories/CenterView/index.tsx delete mode 100644 app/storybook/stories/index.ts diff --git a/.yarn/patches/@animo-id-expo-secure-environment-npm-0.1.5-3c2a8f1b94.patch b/.yarn/patches/@animo-id-expo-secure-environment-npm-0.1.5-3c2a8f1b94.patch new file mode 100644 index 0000000..2628a93 --- /dev/null +++ b/.yarn/patches/@animo-id-expo-secure-environment-npm-0.1.5-3c2a8f1b94.patch @@ -0,0 +1,18 @@ +diff --git a/android/build.gradle b/android/build.gradle +index cde6a970a43cc930546e59a80e8716a0980bc503..f7dc11cd461beedda314f3700dc42623d82a4029 100644 +--- a/android/build.gradle ++++ b/android/build.gradle +@@ -40,6 +40,13 @@ + lintOptions { + abortOnError false + } ++ compileOptions { ++ sourceCompatibility JavaVersion.VERSION_17 ++ targetCompatibility JavaVersion.VERSION_17 ++ } ++ kotlinOptions { ++ jvmTarget = "17" ++ } + } + + dependencies { diff --git a/.yarn/patches/@credo-ts-anoncreds-npm-0.5.17-9f101d8e96.patch b/.yarn/patches/@credo-ts-anoncreds-npm-0.5.17-9f101d8e96.patch deleted file mode 100644 index 656cc45..0000000 --- a/.yarn/patches/@credo-ts-anoncreds-npm-0.5.17-9f101d8e96.patch +++ /dev/null @@ -1,40 +0,0 @@ -diff --git a/build/utils/proofRequest.js b/build/utils/proofRequest.js -index f4ce51a890f0ac41ed1d9806f0350a2114890625..10d02bd809b4e6311618664b0ec4ad0ada8034dc 100644 ---- a/build/utils/proofRequest.js -+++ b/build/utils/proofRequest.js -@@ -7,12 +7,27 @@ function proofRequestUsesUnqualifiedIdentifiers(proofRequest) { - return [ - ...Object.values(proofRequest.requested_attributes), - ...Object.values(proofRequest.requested_predicates), -- ].some((attribute) => attribute.restrictions?.some((restriction) => (restriction.cred_def_id && (0, indyIdentifiers_1.isUnqualifiedCredentialDefinitionId)(restriction.cred_def_id)) || -- (restriction.schema_id && (0, indyIdentifiers_1.isUnqualifiedSchemaId)(restriction.schema_id)) || -- (restriction.issuer_did && (0, indyIdentifiers_1.isUnqualifiedIndyDid)(restriction.issuer_did)) || -- (restriction.issuer_id && (0, indyIdentifiers_1.isUnqualifiedIndyDid)(restriction.issuer_id)) || -- (restriction.schema_issuer_did && (0, indyIdentifiers_1.isUnqualifiedIndyDid)(restriction.schema_issuer_did)) || -- (restriction.schema_issuer_id && (0, indyIdentifiers_1.isUnqualifiedIndyDid)(restriction.schema_issuer_id)) || -- (restriction.rev_reg_id && (0, indyIdentifiers_1.isUnqualifiedRevocationRegistryId)(restriction.rev_reg_id)))); -+ ].some((attribute) => { -+ var _a; -+ return (_a = attribute.restrictions) === null || _a === void 0 ? void 0 : _a.some((restriction) => ( -+ // no qualified identifiers -+ !restriction.cred_def_id && -+ !restriction.schema_id && -+ !restriction.issuer_did && -+ !restriction.issuer_id && -+ !restriction.schema_issuer_did && -+ !restriction.schema_issuer_id && -+ !restriction.rev_reg_id -+ ) || -+ // any unqualified identifiers -+ (restriction.cred_def_id && (0, indyIdentifiers_1.isUnqualifiedCredentialDefinitionId)(restriction.cred_def_id)) || -+ (restriction.schema_id && (0, indyIdentifiers_1.isUnqualifiedSchemaId)(restriction.schema_id)) || -+ (restriction.issuer_did && (0, indyIdentifiers_1.isUnqualifiedIndyDid)(restriction.issuer_did)) || -+ (restriction.issuer_id && (0, indyIdentifiers_1.isUnqualifiedIndyDid)(restriction.issuer_id)) || -+ (restriction.schema_issuer_did && (0, indyIdentifiers_1.isUnqualifiedIndyDid)(restriction.schema_issuer_did)) || -+ (restriction.schema_issuer_id && (0, indyIdentifiers_1.isUnqualifiedIndyDid)(restriction.schema_issuer_id)) || -+ (restriction.rev_reg_id && (0, indyIdentifiers_1.isUnqualifiedRevocationRegistryId)(restriction.rev_reg_id)) -+ ) -+ }) - } - //# sourceMappingURL=proofRequest.js.map -\ No newline at end of file diff --git a/.yarn/patches/@credo-ts-core-npm-0.5.17-c528a69dd8.patch b/.yarn/patches/@credo-ts-core-npm-0.5.17-c528a69dd8.patch deleted file mode 100644 index 6c413d5..0000000 --- a/.yarn/patches/@credo-ts-core-npm-0.5.17-c528a69dd8.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/build/modules/dif-presentation-exchange/DifPresentationExchangeService.js b/build/modules/dif-presentation-exchange/DifPresentationExchangeService.js -index f1723e774dc337b8ceae11cf5765d222fd07ea24..556fcef6877b0248134182551e6b46ebe9a758e4 100644 ---- a/build/modules/dif-presentation-exchange/DifPresentationExchangeService.js -+++ b/build/modules/dif-presentation-exchange/DifPresentationExchangeService.js -@@ -177,7 +177,18 @@ let DifPresentationExchangeService = class DifPresentationExchangeService { - presentationSubmission.descriptor_map.push(...descriptorMap); - }); - return { -- verifiablePresentations: verifiablePresentationResultsWithFormat.flatMap((resultWithFormat) => resultWithFormat.verifiablePresentationResult.verifiablePresentations.map((vp) => (0, utils_2.getVerifiablePresentationFromEncoded)(agentContext, vp))), -+ verifiablePresentations: verifiablePresentationResultsWithFormat.flatMap((resultWithFormat) => { -+ if (resultWithFormat.verifiablePresentationResult.verifiablePresentations) { -+ return resultWithFormat.verifiablePresentationResult.verifiablePresentations.map((vp) => -+ (0, utils_2.getVerifiablePresentationFromEncoded)(agentContext, vp) -+ ) -+ } else { -+ return (0, utils_2.getVerifiablePresentationFromEncoded)( -+ agentContext, -+ resultWithFormat.verifiablePresentationResult.verifiablePresentation -+ ) -+ } -+ }), - presentationSubmission, - presentationSubmissionLocation: verifiablePresentationResultsWithFormat[0].verifiablePresentationResult.presentationSubmissionLocation, - }; diff --git a/.yarn/patches/@credo-ts-indy-vdr-npm-0.5.17-aa0b05041f.patch b/.yarn/patches/@credo-ts-indy-vdr-npm-0.5.17-aa0b05041f.patch deleted file mode 100644 index ee9f0dc..0000000 --- a/.yarn/patches/@credo-ts-indy-vdr-npm-0.5.17-aa0b05041f.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/build/pool/IndyVdrPool.js b/build/pool/IndyVdrPool.js -index 7c157d6754dcba7526100f67dbed3c86b335b0cc..56437364edcb3d16e998fb4766d7b14cae63430f 100644 ---- a/build/pool/IndyVdrPool.js -+++ b/build/pool/IndyVdrPool.js -@@ -17,7 +17,7 @@ class IndyVdrPool { - } - connect() { - if (this._pool) { -- throw new error_1.IndyVdrError('Cannot connect to pool, already connected.'); -+ return; - } - this._pool = new indy_vdr_shared_1.PoolCreate({ - parameters: { diff --git a/.yarn/patches/@credo-ts-react-native-npm-0.6.3-secure-environment-biometrics.patch b/.yarn/patches/@credo-ts-react-native-npm-0.6.3-secure-environment-biometrics.patch new file mode 100644 index 0000000..534f5e5 --- /dev/null +++ b/.yarn/patches/@credo-ts-react-native-npm-0.6.3-secure-environment-biometrics.patch @@ -0,0 +1,68 @@ +diff --git a/build/kms/SecureEnvironmentKeyManagementService.d.mts b/build/kms/SecureEnvironmentKeyManagementService.d.mts +index a24147575a9e37473c63d112d7bb64c79dceaa54..7ff91e5712fed3d4ae4da49d6d7fe54c338e8ba9 100644 +--- a/build/kms/SecureEnvironmentKeyManagementService.d.mts ++++ b/build/kms/SecureEnvironmentKeyManagementService.d.mts +@@ -1,22 +1,27 @@ + import { AgentContext, Kms } from "@credo-ts/core"; + + //#region src/kms/SecureEnvironmentKeyManagementService.d.ts ++interface SecureEnvironmentKeyManagementServiceOptions { ++ biometricsBacked?: boolean; ++} + declare class SecureEnvironmentKeyManagementService implements Kms.KeyManagementService { + readonly backend = "secureEnvironment"; + private readonly secureEnvironment; ++ private readonly options; ++ constructor(options?: SecureEnvironmentKeyManagementServiceOptions); + isOperationSupported(_agentContext: AgentContext, operation: Kms.KmsOperation): boolean; + randomBytes(_agentContext: AgentContext, _options: Kms.KmsRandomBytesOptions): Kms.KmsRandomBytesReturn; + getPublicKey(_agentContext: AgentContext, keyId: string): Promise; + importKey(): Promise>; + deleteKey(_agentContext: AgentContext, options: Kms.KmsDeleteKeyOptions): Promise; + encrypt(): Promise; + decrypt(): Promise; + createKey(_agentContext: AgentContext, options: Kms.KmsCreateKeyOptions): Promise; + sign(_agentContext: AgentContext, options: Kms.KmsSignOptions): Promise; + verify(): Promise; + private publicJwkFromPublicKeyBytes; + private getKeyAsserted; + } + //#endregion +-export { SecureEnvironmentKeyManagementService }; ++export { SecureEnvironmentKeyManagementService, type SecureEnvironmentKeyManagementServiceOptions }; + //# sourceMappingURL=SecureEnvironmentKeyManagementService.d.mts.map +diff --git a/build/kms/SecureEnvironmentKeyManagementService.mjs b/build/kms/SecureEnvironmentKeyManagementService.mjs +index 45aa862698d9d3e164c36d5b61b5977282981983..23d58743281711002c2425d39f0ab1d976d5d911 100644 +--- a/build/kms/SecureEnvironmentKeyManagementService.mjs ++++ b/build/kms/SecureEnvironmentKeyManagementService.mjs +@@ -3,10 +3,11 @@ import { Kms, utils } from "@credo-ts/core"; + + //#region src/kms/SecureEnvironmentKeyManagementService.ts + var SecureEnvironmentKeyManagementService = class { +- constructor() { ++ constructor(options = {}) { + this.backend = "secureEnvironment"; + this.secureEnvironment = importSecureEnvironment(); ++ this.options = { biometricsBacked: true, ...options }; + } + isOperationSupported(_agentContext, operation) { + if (operation.operation === "createKey") return operation.type.kty === "EC" && operation.type.crv === "P-256"; + if (operation.operation === "sign") return operation.algorithm === "ES256"; +@@ -49,7 +50,7 @@ var SecureEnvironmentKeyManagementService = class { + const keyId = options.keyId ?? utils.uuid(); + const secureEnvironment = await this.secureEnvironment; + try { +- await secureEnvironment.generateKeypair(keyId); ++ await secureEnvironment.generateKeypair(keyId, this.options.biometricsBacked); + return { + keyId, + publicJwk: await this.getKeyAsserted(keyId) +@@ -64,7 +65,7 @@ var SecureEnvironmentKeyManagementService = class { + if (options.algorithm !== "ES256") throw new Kms.KeyManagementAlgorithmNotSupportedError(`algorithm '${options.algorithm}'. Only 'ES256' supported.`, this.backend); + const secureEnvironment = await this.secureEnvironment; + try { +- return { signature: await secureEnvironment.sign(options.keyId, options.data) }; ++ return { signature: await secureEnvironment.sign(options.keyId, new Uint8Array(options.data), this.options.biometricsBacked) }; + } catch (error) { + if (error instanceof secureEnvironment.KeyNotFoundError) throw new Kms.KeyManagementKeyNotFoundError(options.keyId, [this.backend]); + throw new Kms.KeyManagementError("Error signing with key", { cause: error }); diff --git a/.yarn/patches/@hyperledger-anoncreds-react-native-npm-0.2.4-644cafe308.patch b/.yarn/patches/@hyperledger-anoncreds-react-native-npm-0.2.4-644cafe308.patch deleted file mode 100644 index 63a99d9..0000000 --- a/.yarn/patches/@hyperledger-anoncreds-react-native-npm-0.2.4-644cafe308.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff --git a/android/CMakeLists.txt b/android/CMakeLists.txt -index 5cc55c5ee3d05cbe9a7b92b0d1b031e0166c7456..3639134c3858f2cad688b6eebf778db8105006d4 100644 ---- a/android/CMakeLists.txt -+++ b/android/CMakeLists.txt -@@ -87,7 +87,15 @@ if(${REACT_NATIVE_VERSION} LESS 71) - ) - endif() - --if(${REACT_NATIVE_VERSION} GREATER_EQUAL 71) -+if(${REACT_NATIVE_VERSION} GREATER_EQUAL 76) -+ # RN 0.76 merged libreactnativejni into a single libreactnative.so prefab target -+ target_link_libraries( -+ ${PACKAGE_NAME} -+ ReactAndroid::jsi -+ ReactAndroid::reactnative -+ fbjni::fbjni -+ ) -+elseif(${REACT_NATIVE_VERSION} GREATER_EQUAL 71) - target_link_libraries( - ${PACKAGE_NAME} - ReactAndroid::jsi diff --git a/.yarn/patches/@hyperledger-aries-askar-react-native-npm-0.2.3-3207b51eab.patch b/.yarn/patches/@hyperledger-aries-askar-react-native-npm-0.2.3-3207b51eab.patch deleted file mode 100644 index 6775de7..0000000 --- a/.yarn/patches/@hyperledger-aries-askar-react-native-npm-0.2.3-3207b51eab.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff --git a/android/CMakeLists.txt b/android/CMakeLists.txt -index 74b6aff9c7cf062724475a58b9030f655a939e18..54b65bc306c926a866c10e74c88a6fff8d1c3eca 100644 ---- a/android/CMakeLists.txt -+++ b/android/CMakeLists.txt -@@ -87,7 +87,15 @@ if(${REACT_NATIVE_VERSION} LESS 71) - ) - endif() - --if(${REACT_NATIVE_VERSION} GREATER_EQUAL 71) -+if(${REACT_NATIVE_VERSION} GREATER_EQUAL 76) -+ # RN 0.76 merged libreactnativejni into a single libreactnative.so prefab target -+ target_link_libraries( -+ ${PACKAGE_NAME} -+ ReactAndroid::jsi -+ ReactAndroid::reactnative -+ fbjni::fbjni -+ ) -+elseif(${REACT_NATIVE_VERSION} GREATER_EQUAL 71) - target_link_libraries( - ${PACKAGE_NAME} - ReactAndroid::jsi diff --git a/.yarn/patches/@hyperledger-indy-vdr-react-native-npm-0.2.2-627d424b96.patch b/.yarn/patches/@hyperledger-indy-vdr-react-native-npm-0.2.2-627d424b96.patch deleted file mode 100644 index cfefbf5..0000000 --- a/.yarn/patches/@hyperledger-indy-vdr-react-native-npm-0.2.2-627d424b96.patch +++ /dev/null @@ -1,194 +0,0 @@ -diff --git a/android/CMakeLists.txt b/android/CMakeLists.txt -index c84556e989cd95a18c5a8296931c8d97671a3c5c..47ef06ff796d4ce0ca0ffd1338dc5dc7965834a9 100644 ---- a/android/CMakeLists.txt -+++ b/android/CMakeLists.txt -@@ -87,7 +87,15 @@ if(${REACT_NATIVE_VERSION} LESS 71) - ) - endif() - --if(${REACT_NATIVE_VERSION} GREATER_EQUAL 71) -+if(${REACT_NATIVE_VERSION} GREATER_EQUAL 76) -+ # RN 0.76 merged libreactnativejni into a single libreactnative.so prefab target -+ target_link_libraries( -+ ${PACKAGE_NAME} -+ ReactAndroid::jsi -+ ReactAndroid::reactnative -+ fbjni::fbjni -+ ) -+elseif(${REACT_NATIVE_VERSION} GREATER_EQUAL 71) - target_link_libraries( - ${PACKAGE_NAME} - ReactAndroid::jsi -diff --git a/android/build.gradle b/android/build.gradle -index 9017d77eb32573415c7922cd83dae5cd792a885f..083320b13d82925625e57b929387a20a6d42c841 100644 ---- a/android/build.gradle -+++ b/android/build.gradle -@@ -59,6 +59,10 @@ def getExt(name) { - return rootProject.ext.get(name) - } - -+def getExtWithFallback(prop, fallback) { -+ return rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback -+} -+ - def resolveBuildType() { - def buildType = "debug" - tasks.all({ task -> -@@ -81,7 +85,7 @@ android { - } - - defaultConfig { -- minSdkVersion 21 -+ minSdkVersion getExtWithFallback('minSdkVersion', '21') - targetSdkVersion getExt('targetSdkVersion') - - externalNativeBuild { -diff --git a/build/NativeBindings.d.ts b/build/NativeBindings.d.ts -index e3106250eb275f591ab53e42dc37cdf888d3406b..f3f2dcd9256d2addeeb4ce83afb3733c9d911f39 100644 ---- a/build/NativeBindings.d.ts -+++ b/build/NativeBindings.d.ts -@@ -11,6 +11,11 @@ export interface NativeBindings { - setCacheDirectory(options: { - path: string; - }): ReturnObject; -+ setLedgerTxnCache(options: { -+ capacity: number; -+ expiry_offset_ms: number; -+ path?: string; -+ }): ReturnObject; - setDefaultLogger(options: Record): ReturnObject; - setProtocolVersion(options: { - version: number; -diff --git a/build/ReactNativeIndyVdr.d.ts b/build/ReactNativeIndyVdr.d.ts -index 034c2d4527ef08eac1941ad784e497a948229ef1..b48eb78bc63c65641bbcf52dce713d4ad7a84a4f 100644 ---- a/build/ReactNativeIndyVdr.d.ts -+++ b/build/ReactNativeIndyVdr.d.ts -@@ -14,6 +14,11 @@ export declare class ReactNativeIndyVdr implements IndyVdr { - setCacheDirectory(options: { - path: string; - }): void; -+ setLedgerTxnCache(options: { -+ capacity: number; -+ expiry_offset_ms: number; -+ path?: string; -+ }): void; - setDefaultLogger(): void; - setProtocolVersion(options: { - version: number; -diff --git a/build/ReactNativeIndyVdr.js b/build/ReactNativeIndyVdr.js -index 16bdc5e8ee395295afa0ec255fee1e2c7a220c57..5fb112fa5df10aeffdd9d42a324702a6b25c3db1 100644 ---- a/build/ReactNativeIndyVdr.js -+++ b/build/ReactNativeIndyVdr.js -@@ -57,6 +57,10 @@ class ReactNativeIndyVdr { - const serializedOptions = (0, serialize_1.serializeArguments)(options); - this.indyVdr.setCacheDirectory(serializedOptions); - } -+ setLedgerTxnCache(options) { -+ const serializedOptions = (0, serialize_1.serializeArguments)(options); -+ this.indyVdr.setLedgerTxnCache(serializedOptions); -+ } - setDefaultLogger() { - this.handleError(this.indyVdr.setDefaultLogger({})); - } -diff --git a/build/ReactNativeIndyVdr.js.map b/build/ReactNativeIndyVdr.js.map -index 219c2d0156e6e3395061e41567831414c320e410..30fb92ec803052f901cf2858be8bda1569196a2c 100644 ---- a/build/ReactNativeIndyVdr.js.map -+++ b/build/ReactNativeIndyVdr.js.map -@@ -1 +1 @@ --{"version":3,"file":"ReactNativeIndyVdr.js","sourceRoot":"","sources":["../src/ReactNativeIndyVdr.ts"],"names":[],"mappings":"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"} -\ No newline at end of file -+{"version":3,"file":"ReactNativeIndyVdr.js","sourceRoot":"","sources":["../src/ReactNativeIndyVdr.ts"],"names":[],"mappings":"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"} -\ No newline at end of file -diff --git a/cpp/HostObject.cpp b/cpp/HostObject.cpp -index dca847963687111473125064c58c90b13f7c718b..c5c5e0a8227314809c31e6565bbecc7cce1c5478 100644 ---- a/cpp/HostObject.cpp -+++ b/cpp/HostObject.cpp -@@ -13,6 +13,7 @@ FunctionMap IndyVdrTurboModuleHostObject::functionMapping(jsi::Runtime &rt) { - fMap.insert(std::make_tuple("getCurrentError", &indyVdr::getCurrentError)); - fMap.insert(std::make_tuple("setConfig", &indyVdr::setConfig)); - fMap.insert(std::make_tuple("setCacheDirectory", &indyVdr::setCacheDirectory)); -+ fMap.insert(std::make_tuple("setLedgerTxnCache", &indyVdr::setLedgerTxnCache)); - fMap.insert(std::make_tuple("setDefaultLogger", &indyVdr::setDefaultLogger)); - fMap.insert( - std::make_tuple("setProtocolVersion", &indyVdr::setProtocolVersion)); -diff --git a/cpp/include/libindy_vdr.h b/cpp/include/libindy_vdr.h -index 7f61bb9faaa119ea74619c82937c8de838992c0a..6ce64ab2a429b940d117b664033f0e3369171eab 100644 ---- a/cpp/include/libindy_vdr.h -+++ b/cpp/include/libindy_vdr.h -@@ -481,6 +481,8 @@ ErrorCode indy_vdr_resolve(PoolHandle pool_handle, - - ErrorCode indy_vdr_set_cache_directory(FfiStr path); - -+ErrorCode indy_vdr_set_ledger_txn_cache(int32_t capacity, int64_t expiry_offset_ms, FfiStr path); -+ - ErrorCode indy_vdr_set_config(FfiStr config); - - ErrorCode indy_vdr_set_default_logger(void); -diff --git a/cpp/indyVdr.cpp b/cpp/indyVdr.cpp -index 0e3002cc6b504743ac70e777e52c387e26067bda..706134f8ccad62a790ee2f85a0f7b306cdfa5c85 100644 ---- a/cpp/indyVdr.cpp -+++ b/cpp/indyVdr.cpp -@@ -32,6 +32,16 @@ jsi::Value setCacheDirectory(jsi::Runtime &rt, jsi::Object options) { - return createReturnValue(rt, code, nullptr); - }; - -+jsi::Value setLedgerTxnCache(jsi::Runtime &rt, jsi::Object options) { -+ auto capacity = jsiToValue(rt, options, "capacity"); -+ auto expiry_offset_ms = jsiToValue(rt, options, "expiry_offset_ms"); -+ auto path = jsiToValue(rt, options, "path", true); -+ -+ ErrorCode code = indy_vdr_set_ledger_txn_cache(capacity, expiry_offset_ms, path.length() > 0 ? path.c_str() : nullptr); -+ -+ return createReturnValue(rt, code, nullptr); -+}; -+ - jsi::Value setDefaultLogger(jsi::Runtime &rt, jsi::Object options) { - ErrorCode code = indy_vdr_set_default_logger(); - -diff --git a/cpp/indyVdr.h b/cpp/indyVdr.h -index fa48a9253770faf2007913890f8458ffb26864f4..c708f3d483ff71dc90fe54af1a2b2eb087c58b26 100644 ---- a/cpp/indyVdr.h -+++ b/cpp/indyVdr.h -@@ -13,6 +13,7 @@ jsi::Value version(jsi::Runtime &rt, jsi::Object options); - jsi::Value getCurrentError(jsi::Runtime &rt, jsi::Object options); - jsi::Value setConfig(jsi::Runtime &rt, jsi::Object options); - jsi::Value setCacheDirectory(jsi::Runtime &rt, jsi::Object options); -+jsi::Value setLedgerTxnCache(jsi::Runtime &rt, jsi::Object options); - jsi::Value setDefaultLogger(jsi::Runtime &rt, jsi::Object options); - jsi::Value setProtocolVersion(jsi::Runtime &rt, jsi::Object options); - jsi::Value setSocksProxy(jsi::Runtime &rt, jsi::Object options); -diff --git a/cpp/turboModuleUtility.cpp b/cpp/turboModuleUtility.cpp -index 3ff7d9a455748748d84abf076dc29166bd94a717..5a029ea34225d5bb9f5610270677d5ffda80203a 100644 ---- a/cpp/turboModuleUtility.cpp -+++ b/cpp/turboModuleUtility.cpp -@@ -143,7 +143,7 @@ int64_t jsiToValue(jsi::Runtime &rt, jsi::Object &options, const char *name, - bool optional) { - jsi::Value value = options.getProperty(rt, name); - if ((value.isNull() || value.isUndefined()) && optional) -- return 0; -+ return -1; - - if (value.isNumber()) - return value.asNumber(); -@@ -169,7 +169,7 @@ int32_t jsiToValue(jsi::Runtime &rt, jsi::Object &options, const char *name, - bool optional) { - jsi::Value value = options.getProperty(rt, name); - if ((value.isNull() || value.isUndefined()) && optional) -- return 0; -+ return -1; - - if (value.isNumber()) - return value.asNumber(); -diff --git a/package.json b/package.json -index 084a7146e124e07cd3860819b9211be7d2369806..b911f8c6c360caea06946a3076e5148d5018c6ed 100644 ---- a/package.json -+++ b/package.json -@@ -58,7 +58,7 @@ - "binary": { - "module_name": "indy_vdr", - "module_path": "native", -- "remote_path": "v0.4.1", -+ "remote_path": "v0.4.3", - "host": "https://github.com/hyperledger/indy-vdr/releases/download/", - "package_name": "library-ios-android.tar.gz" - }, diff --git a/.yarn/patches/@hyperledger-indy-vdr-react-native-npm-0.2.4-d7ed0b15da.patch b/.yarn/patches/@hyperledger-indy-vdr-react-native-npm-0.2.4-d7ed0b15da.patch new file mode 100644 index 0000000..d7260d5 --- /dev/null +++ b/.yarn/patches/@hyperledger-indy-vdr-react-native-npm-0.2.4-d7ed0b15da.patch @@ -0,0 +1,22 @@ +diff --git a/cpp/turboModuleUtility.cpp b/cpp/turboModuleUtility.cpp +index 3ff7d9a455748748d84abf076dc29166bd94a717..5a029ea34225d5bb9f5610270677d5ffda80203a 100644 +--- a/cpp/turboModuleUtility.cpp ++++ b/cpp/turboModuleUtility.cpp +@@ -143,7 +143,7 @@ int64_t jsiToValue(jsi::Runtime &rt, jsi::Object &options, const char *name, + bool optional) { + jsi::Value value = options.getProperty(rt, name); + if ((value.isNull() || value.isUndefined()) && optional) +- return 0; ++ return -1; + + if (value.isNumber()) + return value.asNumber(); +@@ -169,7 +169,7 @@ int32_t jsiToValue(jsi::Runtime &rt, jsi::Object &options, const char *name, + bool optional) { + jsi::Value value = options.getProperty(rt, name); + if ((value.isNull() || value.isUndefined()) && optional) +- return 0; ++ return -1; + + if (value.isNumber()) + return value.asNumber(); diff --git a/.yarn/patches/@hyperledger-indy-vdr-shared-npm-0.2.2-b989282fc6.patch b/.yarn/patches/@hyperledger-indy-vdr-shared-npm-0.2.2-b989282fc6.patch deleted file mode 100644 index 99e2283..0000000 --- a/.yarn/patches/@hyperledger-indy-vdr-shared-npm-0.2.2-b989282fc6.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff --git a/build/types/IndyVdr.d.ts b/build/types/IndyVdr.d.ts -index 99f5d50a851462c8c41e52ceb49795feebce0b4e..3aa7890e1f3c422daa6ec82fd6b42d0b924d18b5 100644 ---- a/build/types/IndyVdr.d.ts -+++ b/build/types/IndyVdr.d.ts -@@ -11,6 +11,11 @@ export interface IndyVdr { - setCacheDirectory(options: { - path: string; - }): void; -+ setLedgerTxnCache(options: { -+ capacity: number; -+ expiry_offset_ms: number; -+ path?: string; -+ }): void; - setDefaultLogger(): void; - setProtocolVersion(options: { - version: number; diff --git a/UPGRADE_PROGRESS.md b/UPGRADE_PROGRESS.md index 887904e..41f5e3b 100644 --- a/UPGRADE_PROGRESS.md +++ b/UPGRADE_PROGRESS.md @@ -4,7 +4,7 @@ > effort with zero conversation context. Update it at every phase gate and whenever a > significant decision or discovery is made. Keep it factual and current. -Last updated: 2026-07-04 (Phase 2 COMPLETE — RN 0.77.3, BCSC dropped, E2E green both platforms) +Last updated: 2026-07-06 (Phase 3 app JS layer GREEN — RN 0.81.5/React 19.1/credo 0.6.3 typecheck+lint+jest pass on `upgrade/phase3-bifold3`; native Android/iOS builds next) --- @@ -267,15 +267,60 @@ babel/metro/jest configs, `.env.sample`. - PHASE 2 GATE PASSED: app jest 14/27 PASS, bifold core jest 134 suites / 1242 PASS, Android + iOS build PASS, two-device E2E VRC exchange PASS on Android and iOS. - [ ] **Phase 3 — Big hop: bifold 3.0.16 + credo 0.6.3 + React 19 + RN 0.81** - - In `bifold/`: new branch `upgrade/bifold-3.x` = upstream v3.0.16 content; port §5.1 delta - onto it. Mechanical credo API rewrite everywhere: `agent.credentials` → - `agent.modules.credentials`, explicit DIDComm module registration, askar rename. - - Attestation package: start from upstream 3.0.16 version, re-apply Keyring crypto/signing. - - App: RN 0.81 + React 19 (reference: bc-wallet-mobile main), drop Storybook. - - New Architecture: try `newArchEnabled=true` (upstream default); custom native modules - (attestation) must be audited; fall back to false if needed, but record it. - - Adopt upstream patch set; wallet-open/migration smoke test (askar store compat). - - Gate: VRC conformance tests green, jest green, both bundle, E2E green. + - [x] In `bifold/`: branch `upgrade/bifold-3.x` = upstream v3.0.16 content; §5.1 delta ported + (commit `68d9da80`). Credo 0.6.3 migration done (commit `cdb9289c`): DIDComm APIs under + `agent.modules.didcomm`, `DidCommModule` carries connections/credentials/proofs/oob/ + mediation config, renamed types/events (`DidCommConnectionRecord` etc.), + `kms.importKey` + `dids.create createKey` (JWK types) replace `wallet.createKey`, + askar renamed to `@openwallet-foundation/askar-*`, `W3cCredentialRecord.encoded` + replaces private `.credential`. witness-server + vrc-reference fully migrated + (sources AND unit tests — mock agents alias didcomm APIs under `modules.didcomm`; + jest needs babel-jest ESM transform for credo 0.6 `.mjs` builds, see the two + jest.config.js files). `receiveInvitationFromUrl` now REQUIRES a `label` in its + 2nd config arg (credo 0.6 moved agent label out of InitConfig). + - [x] bifold gate: `yarn build` 0 TS errors, lint + prettier clean, + `yarn coverage` 155 suites / 1398 tests PASS (core 1400 incl. 2 skipped, + vrc-reference 105, witness-server, vrc-shared). One flaky suite noted: + CredentialDetails.test.tsx can fail under full-run load (act() timing), passes + isolated and on rerun. + - [x] Pushed + PR opened: berkmancenter/keyring-bifold#26 (upgrade/bifold-3.x → main). + NOTE: branch-swap made history disjoint from fork main; fixed with a signed + tie-merge commit (`git commit-tree -S` with two parents, tree = Phase 3 tree). + DO NOT merge without Alberto's approval. + - [x] Attestation package: rebuilt from upstream 3.0.16 base, Keyring crypto re-applied. + - [x] App JS layer: RN 0.81.5 + React 19.1.0 wired, bifold 3.0.16 portals (incl. new + `@bifold/react-hooks` — `@credo-ts/react-hooks` is gone), credo 0.6.3 deps, + askar → `@openwallet-foundation/askar-react-native` 0.6.0, Storybook dropped + (dir + AppStorybook.tsx removed), branch `upgrade/phase3-bifold3`. Highlights: + - `bc-agent-modules.ts` rewritten for credo 0.6 (`DidCommModule` config, + `Kms.KeyManagementModule` with askar + expo secure-environment services, + explicit JSON-LD/AnonCreds DIDComm format services, VRC document loader). + - `useBCAgentSetup.ts`: wallet id/key now live in `AskarModule` store config — + no more `agent.wallet.open()`; transports register via + `agent.modules.didcomm.registerOutboundTransport`; indy-vdr pool warm-up + guards the BC-patch-only methods (`refreshPoolConnections`). + - DRPC-based BC attestation flow REMOVED (`@credo-ts/drpc` has no stable 0.6.x; + Keyring doesn't run BC's attestation service). `AttestationMonitor` keeps the + bifold interface; `requestAttestationCredential` now emits FailedRequestCredential. + `app/src/utils/drpc.ts` deleted. + - proofs/credentials API options renamed: `proofRecordId`→`proofExchangeRecordId`, + `credentialRecordId`→`credentialExchangeRecordId`. + - jest: transformIgnorePatterns synced with bifold core (credo .mjs, @noble, + @stablelib, expo...); `@bifold/*` mapped to bifold SOURCES (lib/commonjs build + has a circular-require bug under jest); reanimated mocked via official mock; + RN 0.81 Keyboard/BackHandler mocks ported from bifold jestSetup. + - babel: module-resolver `root: ['.']` REMOVED (it rewrote `from '.'` imports + inside node_modules to app root index.js under jest); added + `@babel/plugin-transform-export-namespace-from` + reanimated plugin. + - Fixed upstream bug in bifold `store.ts` (absolute `components/views/Banner` + import breaks consumers compiling core from source). + - [x] App gate (JS): typecheck 0 errors, eslint clean, jest 14 suites / 27 tests PASS + (6 snapshots updated for RN 0.81 Pressable/style flattening). + - [ ] Android + iOS native builds: NOT STARTED (Gradle/Podfile still on RN 0.72 — + native project upgrade is next). New Architecture: try `newArchEnabled=true` + (upstream default); audit attestation native module; fall back if needed. + - [ ] Wallet-open/migration smoke test (askar store compat 0.2→0.6). + - [ ] Gate: VRC conformance tests green, jest green, both platforms bundle, E2E green. - [ ] **Phase 4 — App-layer upstream sync** (port wanted bc-wallet-mobile improvements; containers/DI, screens). Gate: full suite + E2E. - [ ] **Phase 5 — VC 2.0 for VRC** (secondary goal) diff --git a/app/AppStorybook.tsx b/app/AppStorybook.tsx deleted file mode 100644 index 41ec751..0000000 --- a/app/AppStorybook.tsx +++ /dev/null @@ -1,18 +0,0 @@ -// import { initLanguages } from '@bifold/core' -import React from 'react' -import { LogBox } from 'react-native' - -// import keyring from './src' -import StorybookUIRoot from './storybook' - -// const { localization } = keyring - -// initLanguages(localization) - -LogBox.ignoreAllLogs() - -const Base = () => { - return -} - -export default Base diff --git a/app/__mocks__/@credo-ts/react-hooks.ts b/app/__mocks__/@bifold/react-hooks.ts similarity index 87% rename from app/__mocks__/@credo-ts/react-hooks.ts rename to app/__mocks__/@bifold/react-hooks.ts index 50bb0cf..3c75943 100644 --- a/app/__mocks__/@credo-ts/react-hooks.ts +++ b/app/__mocks__/@bifold/react-hooks.ts @@ -1,6 +1,10 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { LegacyIndyCredentialFormat } from '@credo-ts/anoncreds' -import { CredentialExchangeRecord, CredentialProtocolOptions, ProofExchangeRecord } from '@credo-ts/core' +import { + CredentialProtocolOptions, + DidCommCredentialExchangeRecord as CredentialExchangeRecord, + DidCommProofExchangeRecord as ProofExchangeRecord, +} from '@credo-ts/didcomm' const useCredentials = jest.fn().mockReturnValue({ credentials: [] } as any) const useCredentialByState = jest.fn().mockReturnValue([] as CredentialExchangeRecord[]) diff --git a/app/__tests__/components/__snapshots__/EmptyList.test.tsx.snap b/app/__tests__/components/__snapshots__/EmptyList.test.tsx.snap index 88a6520..a61f7d3 100644 --- a/app/__tests__/components/__snapshots__/EmptyList.test.tsx.snap +++ b/app/__tests__/components/__snapshots__/EmptyList.test.tsx.snap @@ -120,9 +120,7 @@ exports[`EmptyList Component renders correctly 1`] = ` accessible={true} collapsable={false} focusable={true} - onBlur={[Function]} onClick={[Function]} - onFocus={[Function]} onResponderGrant={[Function]} onResponderMove={[Function]} onResponderRelease={[Function]} @@ -130,29 +128,22 @@ exports[`EmptyList Component renders correctly 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - [ - { - "overflow": "hidden", - }, - { - "backgroundColor": "#622C62", - "borderRadius": 10, - "elevation": 4, - "padding": 16, - "paddingHorizontal": 16, - "paddingVertical": 12, - "shadowColor": "#000000", - "shadowOffset": { - "height": 4, - "width": 0, - }, - "shadowOpacity": 0.15, - "shadowRadius": 4, + { + "backgroundColor": "#622C62", + "borderRadius": 10, + "elevation": 4, + "opacity": 1, + "padding": 16, + "paddingHorizontal": 16, + "paddingVertical": 12, + "shadowColor": "#000000", + "shadowOffset": { + "height": 4, + "width": 0, }, - false, - false, - false, - ] + "shadowOpacity": 0.15, + "shadowRadius": 4, + } } testID="com.ariesbifold:id/AddFirstCredential" > @@ -186,7 +177,6 @@ exports[`EmptyList Component renders correctly 1`] = ` }, false, false, - false, ], ] } diff --git a/app/__tests__/navigation/__snapshots__/QRCodeFlow.test.tsx.snap b/app/__tests__/navigation/__snapshots__/QRCodeFlow.test.tsx.snap index 2d34fa8..11d67ad 100644 --- a/app/__tests__/navigation/__snapshots__/QRCodeFlow.test.tsx.snap +++ b/app/__tests__/navigation/__snapshots__/QRCodeFlow.test.tsx.snap @@ -3,7 +3,6 @@ exports[`QR Code Flow Integration QRCodeExchangeSlider renders correctly in AdvancedIdentity context 1`] = ` @@ -255,20 +257,22 @@ exports[`QR Code Flow Integration QRCodeExchangeSlider renders correctly in Adva style={ [ { - "color": "#FFFFFF", + "color": "#4A4A4A", + "fontFamily": "SourceSans3-Regular", "fontSize": 18, "fontWeight": "normal", }, [ { "color": "#FFFFFF", + "fontFamily": "SourceSans3-Regular", "fontSize": 18, "fontWeight": "bold", + "lineHeight": 24, "textAlign": "center", }, false, false, - false, ], ] } @@ -308,9 +312,7 @@ exports[`QR Code Flow Integration QRCodeExchangeSlider renders correctly in Adva accessible={true} collapsable={false} focusable={true} - onBlur={[Function]} onClick={[Function]} - onFocus={[Function]} onResponderGrant={[Function]} onResponderMove={[Function]} onResponderRelease={[Function]} @@ -318,19 +320,20 @@ exports[`QR Code Flow Integration QRCodeExchangeSlider renders correctly in Adva onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - [ - { - "overflow": "hidden", - }, - { - "backgroundColor": "#42803E", - "borderRadius": 4, - "padding": 16, + { + "backgroundColor": "#622C62", + "borderRadius": 10, + "elevation": 4, + "opacity": 1, + "padding": 16, + "shadowColor": "#000000", + "shadowOffset": { + "height": 4, + "width": 0, }, - false, - false, - false, - ] + "shadowOpacity": 0.15, + "shadowRadius": 4, + } } testID="com.ariesbifold:id/GenerateQRCode" > @@ -348,20 +351,22 @@ exports[`QR Code Flow Integration QRCodeExchangeSlider renders correctly in Adva style={ [ { - "color": "#FFFFFF", + "color": "#4A4A4A", + "fontFamily": "SourceSans3-Regular", "fontSize": 18, "fontWeight": "normal", }, [ { "color": "#FFFFFF", + "fontFamily": "SourceSans3-Regular", "fontSize": 18, "fontWeight": "bold", + "lineHeight": 24, "textAlign": "center", }, false, false, - false, ], ] } diff --git a/app/__tests__/navigation/__snapshots__/TabNavigation.test.tsx.snap b/app/__tests__/navigation/__snapshots__/TabNavigation.test.tsx.snap index 66236ca..cd990ef 100644 --- a/app/__tests__/navigation/__snapshots__/TabNavigation.test.tsx.snap +++ b/app/__tests__/navigation/__snapshots__/TabNavigation.test.tsx.snap @@ -3,7 +3,6 @@ exports[`Tab Navigation Integration QRCodeExchangeSlider renders correctly 1`] = ` @@ -255,20 +257,22 @@ exports[`Tab Navigation Integration QRCodeExchangeSlider renders correctly 1`] = style={ [ { - "color": "#FFFFFF", + "color": "#4A4A4A", + "fontFamily": "SourceSans3-Regular", "fontSize": 18, "fontWeight": "normal", }, [ { "color": "#FFFFFF", + "fontFamily": "SourceSans3-Regular", "fontSize": 18, "fontWeight": "bold", + "lineHeight": 24, "textAlign": "center", }, false, false, - false, ], ] } @@ -308,9 +312,7 @@ exports[`Tab Navigation Integration QRCodeExchangeSlider renders correctly 1`] = accessible={true} collapsable={false} focusable={true} - onBlur={[Function]} onClick={[Function]} - onFocus={[Function]} onResponderGrant={[Function]} onResponderMove={[Function]} onResponderRelease={[Function]} @@ -318,19 +320,20 @@ exports[`Tab Navigation Integration QRCodeExchangeSlider renders correctly 1`] = onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - [ - { - "overflow": "hidden", - }, - { - "backgroundColor": "#42803E", - "borderRadius": 4, - "padding": 16, + { + "backgroundColor": "#622C62", + "borderRadius": 10, + "elevation": 4, + "opacity": 1, + "padding": 16, + "shadowColor": "#000000", + "shadowOffset": { + "height": 4, + "width": 0, }, - false, - false, - false, - ] + "shadowOpacity": 0.15, + "shadowRadius": 4, + } } testID="com.ariesbifold:id/GenerateQRCode" > @@ -348,20 +351,22 @@ exports[`Tab Navigation Integration QRCodeExchangeSlider renders correctly 1`] = style={ [ { - "color": "#FFFFFF", + "color": "#4A4A4A", + "fontFamily": "SourceSans3-Regular", "fontSize": 18, "fontWeight": "normal", }, [ { "color": "#FFFFFF", + "fontFamily": "SourceSans3-Regular", "fontSize": 18, "fontWeight": "bold", + "lineHeight": 24, "textAlign": "center", }, false, false, - false, ], ] } diff --git a/app/__tests__/screens/__snapshots__/Developer.test.tsx.snap b/app/__tests__/screens/__snapshots__/Developer.test.tsx.snap index 4df73c2..05d9fc2 100644 --- a/app/__tests__/screens/__snapshots__/Developer.test.tsx.snap +++ b/app/__tests__/screens/__snapshots__/Developer.test.tsx.snap @@ -103,8 +103,7 @@ exports[`Developer Screen screen renders correctly 1`] = ` style={ [ { - "height": 31, - "width": 51, + "alignSelf": "flex-start", }, { "backgroundColor": "#D3D3D3", @@ -358,8 +357,7 @@ exports[`Developer Screen screen renders correctly 1`] = ` style={ [ { - "height": 31, - "width": 51, + "alignSelf": "flex-start", }, { "backgroundColor": "#D3D3D3", @@ -469,8 +467,7 @@ exports[`Developer Screen screen renders correctly 1`] = ` style={ [ { - "height": 31, - "width": 51, + "alignSelf": "flex-start", }, { "backgroundColor": "#D3D3D3", @@ -580,8 +577,7 @@ exports[`Developer Screen screen renders correctly 1`] = ` style={ [ { - "height": 31, - "width": 51, + "alignSelf": "flex-start", }, { "backgroundColor": "#D3D3D3", @@ -691,8 +687,7 @@ exports[`Developer Screen screen renders correctly 1`] = ` style={ [ { - "height": 31, - "width": 51, + "alignSelf": "flex-start", }, { "backgroundColor": "#D3D3D3", @@ -802,8 +797,7 @@ exports[`Developer Screen screen renders correctly 1`] = ` style={ [ { - "height": 31, - "width": 51, + "alignSelf": "flex-start", }, { "backgroundColor": "#D3D3D3", @@ -913,8 +907,7 @@ exports[`Developer Screen screen renders correctly 1`] = ` style={ [ { - "height": 31, - "width": 51, + "alignSelf": "flex-start", }, { "backgroundColor": "#D3D3D3", @@ -1024,8 +1017,7 @@ exports[`Developer Screen screen renders correctly 1`] = ` style={ [ { - "height": 31, - "width": 51, + "alignSelf": "flex-start", }, { "backgroundColor": "#D3D3D3", @@ -1119,8 +1111,7 @@ exports[`Developer Screen screen renders correctly 1`] = ` style={ [ { - "height": 31, - "width": 51, + "alignSelf": "flex-start", }, { "backgroundColor": "#D3D3D3", @@ -1213,8 +1204,7 @@ exports[`Developer Screen screen renders correctly 1`] = ` style={ [ { - "height": 31, - "width": 51, + "alignSelf": "flex-start", }, { "backgroundColor": "#D3D3D3", @@ -1307,8 +1297,7 @@ exports[`Developer Screen screen renders correctly 1`] = ` style={ [ { - "height": 31, - "width": 51, + "alignSelf": "flex-start", }, { "backgroundColor": "#D3D3D3", diff --git a/app/__tests__/screens/__snapshots__/PersonCredential.test.tsx.snap b/app/__tests__/screens/__snapshots__/PersonCredential.test.tsx.snap index 4ce7526..a496c43 100644 --- a/app/__tests__/screens/__snapshots__/PersonCredential.test.tsx.snap +++ b/app/__tests__/screens/__snapshots__/PersonCredential.test.tsx.snap @@ -107,9 +107,7 @@ exports[`Person Credential Screen screen renders correctly 1`] = ` accessible={true} collapsable={false} focusable={true} - onBlur={[Function]} onClick={[Function]} - onFocus={[Function]} onResponderGrant={[Function]} onResponderMove={[Function]} onResponderRelease={[Function]} @@ -117,29 +115,22 @@ exports[`Person Credential Screen screen renders correctly 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - [ - { - "overflow": "hidden", - }, - { - "backgroundColor": "#622C62", - "borderRadius": 10, - "elevation": 4, - "padding": 16, - "paddingHorizontal": 16, - "paddingVertical": 12, - "shadowColor": "#000000", - "shadowOffset": { - "height": 4, - "width": 0, - }, - "shadowOpacity": 0.15, - "shadowRadius": 4, + { + "backgroundColor": "#622C62", + "borderRadius": 10, + "elevation": 4, + "opacity": 1, + "padding": 16, + "paddingHorizontal": 16, + "paddingVertical": 12, + "shadowColor": "#000000", + "shadowOffset": { + "height": 4, + "width": 0, }, - false, - false, - false, - ] + "shadowOpacity": 0.15, + "shadowRadius": 4, + } } testID="com.ariesbifold:id/InstallApp" > @@ -173,7 +164,6 @@ exports[`Person Credential Screen screen renders correctly 1`] = ` }, false, false, - false, ], ] } diff --git a/app/__tests__/screens/__snapshots__/RemoteLogWarning.test.tsx.snap b/app/__tests__/screens/__snapshots__/RemoteLogWarning.test.tsx.snap index 69f937f..b5e5475 100644 --- a/app/__tests__/screens/__snapshots__/RemoteLogWarning.test.tsx.snap +++ b/app/__tests__/screens/__snapshots__/RemoteLogWarning.test.tsx.snap @@ -412,7 +412,6 @@ exports[`RemoteLogWarning Screen screen renders correctly 1`] = ` style={ { "alignItems": "center", - "flex": 1, "flexDirection": "row-reverse", "margin": 10, } @@ -544,10 +543,8 @@ exports[`RemoteLogWarning Screen screen renders correctly 1`] = ` } accessible={true} collapsable={false} - focusable={true} - onBlur={[Function]} + focusable={false} onClick={[Function]} - onFocus={[Function]} onResponderGrant={[Function]} onResponderMove={[Function]} onResponderRelease={[Function]} @@ -555,35 +552,22 @@ exports[`RemoteLogWarning Screen screen renders correctly 1`] = ` onResponderTerminationRequest={[Function]} onStartShouldSetResponder={[Function]} style={ - [ - { - "overflow": "hidden", - }, - { - "backgroundColor": "#622C62", - "borderRadius": 10, - "elevation": 4, - "padding": 16, - "paddingHorizontal": 16, - "paddingVertical": 12, - "shadowColor": "#000000", - "shadowOffset": { - "height": 4, - "width": 0, - }, - "shadowOpacity": 0.15, - "shadowRadius": 4, - }, - { - "backgroundColor": "rgba(98, 44, 98, 0.7)", - "borderRadius": 10, - "padding": 16, - "paddingHorizontal": 16, - "paddingVertical": 12, + { + "backgroundColor": "rgba(98, 44, 98, 0.7)", + "borderRadius": 10, + "elevation": 4, + "opacity": 1, + "padding": 16, + "paddingHorizontal": 16, + "paddingVertical": 12, + "shadowColor": "#000000", + "shadowOffset": { + "height": 4, + "width": 0, }, - false, - false, - ] + "shadowOpacity": 0.15, + "shadowRadius": 4, + } } testID="com.ariesbifold:id/TurnOn" > @@ -624,7 +608,6 @@ exports[`RemoteLogWarning Screen screen renders correctly 1`] = ` "textAlign": "center", }, false, - false, ], ] } diff --git a/app/__tests__/utils/periodicPickup.test.ts b/app/__tests__/utils/periodicPickup.test.ts index 807fe12..9d97ff3 100644 --- a/app/__tests__/utils/periodicPickup.test.ts +++ b/app/__tests__/utils/periodicPickup.test.ts @@ -1,15 +1,21 @@ -import { Agent } from '@credo-ts/core' import { startPeriodicTrustPing } from '@utils/mediator' jest.useFakeTimers({ legacyFakeTimers: true }) -const createMockAgent = () => - ({ - mediationRecipient: { - findDefaultMediator: jest.fn().mockResolvedValue({ connectionId: 'mock-mediator-conn-id' }), - }, - connections: { - sendPing: jest.fn().mockResolvedValue(undefined), +const createMockAgent = () => { + const mediationRecipient = { + findDefaultMediator: jest.fn().mockResolvedValue({ connectionId: 'mock-mediator-conn-id' }), + } + const connections = { + sendPing: jest.fn().mockResolvedValue(undefined), + } + return { + // credo 0.6: didcomm APIs live under agent.modules.didcomm; keep the + // top-level aliases so test assertions can reference the same mocks + mediationRecipient, + connections, + modules: { + didcomm: { mediationRecipient, connections }, }, config: { logger: { @@ -17,10 +23,11 @@ const createMockAgent = () => error: jest.fn(), }, }, - } as unknown as Agent) + } as any +} describe('startPeriodicTrustPing', () => { - let mockAgent: Agent + let mockAgent: any beforeEach(() => { jest.clearAllTimers() diff --git a/app/babel.config.js b/app/babel.config.js index 5b6cac5..89fb8b7 100644 --- a/app/babel.config.js +++ b/app/babel.config.js @@ -1,10 +1,13 @@ const presets = ['module:@react-native/babel-preset'] const plugins = [ + '@babel/plugin-transform-export-namespace-from', [ 'module-resolver', { - root: ['.'], - extensions: ['.tsx', 'ts'], + // NOTE: no `root` here on purpose - with root: ['.'] module-resolver + // rewrites `from '.'` imports inside node_modules (e.g. gesture-handler's + // ReanimatedSwipeable) to the app root index.js, breaking jest + extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'], alias: { '@': './src', '@assets': './src/assets', @@ -25,6 +28,9 @@ if (process.env['ENV'] === 'prod') { plugins.push('transform-remove-console') } +// react-native-reanimated plugin must be listed last +plugins.push('react-native-reanimated/plugin') + module.exports = { presets, plugins, diff --git a/app/jest.config.js b/app/jest.config.js index e0e33aa..447992e 100644 --- a/app/jest.config.js +++ b/app/jest.config.js @@ -16,9 +16,16 @@ module.exports = { '^uuid$': require.resolve('uuid'), '@credo-ts/core': require.resolve('@credo-ts/core'), '@credo-ts/anoncreds': require.resolve('@credo-ts/anoncreds'), - '@bifold/core': require.resolve('@bifold/core'), + '@credo-ts/didcomm': require.resolve('@credo-ts/didcomm'), + // Use bifold sources directly (like bifold's own jest configs) to avoid + // circular-require issues in the lib/commonjs build under jest + '^@bifold/core$': '/../bifold/packages/core/src/index.ts', + '^@bifold/verifier$': '/../bifold/packages/verifier/src/index.ts', + '^@bifold/oca/build/legacy$': '/../bifold/packages/oca/src/legacy/index.ts', + '^@bifold/oca$': '/../bifold/packages/oca/src/index.ts', + '^@bifold/react-hooks$': '/../bifold/packages/react-hooks/src/index.ts', '@bifold/remote-logs': '/__mocks__/@bifold/remote-logs.ts', - '@hyperledger/aries-askar-react-native': require.resolve('@hyperledger/aries-askar-react-native'), + '@openwallet-foundation/askar-react-native': require.resolve('@openwallet-foundation/askar-react-native'), // CRITICAL: Force Jest to use app's React instead of bifold's // Multiple copies of React cause "Invalid hook call" errors '^react$': require.resolve('react'), @@ -27,6 +34,11 @@ module.exports = { // When portal: follows symlink to bifold, it can resolve packages from bifold's node_modules // This ensures tests use app's versions with proper mocks from jestSetup.js '^react-native$': require.resolve('react-native'), + // Also map react-native subpath imports (e.g. react-native/Libraries/...) + // so bifold sources can't drag in bifold/node_modules' second RN copy + '^react-native/(.*)$': `${require('path').dirname(require.resolve('react-native/package.json'))}/$1`, + '^react-native-reanimated$': require.resolve('react-native-reanimated'), + '^react-native-keyboard-controller$': require.resolve('react-native-keyboard-controller'), '^react-native-splash-screen$': require.resolve('react-native-splash-screen'), '^react-native-toast-message$': require.resolve('react-native-toast-message'), '^react-native-device-info$': require.resolve('react-native-device-info'), @@ -53,12 +65,15 @@ module.exports = { '^react-native-screenguard$': require.resolve('react-native-screenguard'), '^react-native-tcp-socket$': require.resolve('react-native-tcp-socket'), '^react-native-vector-icons$': require.resolve('react-native-vector-icons'), + // Expo modules used by bifold core - reuse bifold's jest mocks + 'expo-crypto': '/../bifold/packages/core/__mocks__/@expo/expo-crypto.js', + '@expo/app-integrity': '/../bifold/packages/core/__mocks__/@expo/app-integrity.js', }, transform: { - '^.+\\.(js|jsx|ts|tsx)$': 'babel-jest', + '^.+\\.(js|jsx|ts|tsx|mjs)$': 'babel-jest', }, transformIgnorePatterns: [ - 'node_modules\\/(?!(.*react-native.*)|(uuid)|(@aries-framework\\/core)|(@aries-framework\\/anoncreds)|(@hyperledger\\/aries-bifold-core))', + 'node_modules/(?!(.*react-native.*|@credo-ts|@openwallet-foundation|@openid4vc|@noble|@stablelib|@digitalcredentials|dcql|valibot|query-string|decode-uri-component|filter-obj|split-on-first|uuid|@bifold|expo(nent)?|@expo(nent)?/.*)/)', ], testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$', testPathIgnorePatterns: ['\\.snap$', '/node_modules/', '/lib', '/__tests__/contexts/'], diff --git a/app/jestSetup.js b/app/jestSetup.js index 6f2e40e..36ce43f 100644 --- a/app/jestSetup.js +++ b/app/jestSetup.js @@ -25,5 +25,56 @@ jest.mock('react-native-permissions', () => require('react-native-permissions/mo jest.mock('react-native-splash-screen', () => ({})) jest.mock('@bifold/react-native-attestation', () => ({})) jest.mock('@hyperledger/anoncreds-react-native', () => ({})) -jest.mock('@hyperledger/aries-askar-react-native', () => ({})) +jest.mock('@openwallet-foundation/askar-react-native', () => ({})) jest.mock('@hyperledger/indy-vdr-react-native', () => ({})) + +// React 18+/19: enable proper act() behavior in tests +globalThis.IS_REACT_ACT_ENVIRONMENT = true + +jest.mock('react-native-reanimated', () => require('react-native-reanimated/mock')) + +// Mirror bifold's jestSetup: keep RefreshOrchestrator from spinning timers/logs +jest.mock('../bifold/packages/core/src/modules/openid/refresh/RefreshOrchestrator', () => ({ + RefreshOrchestrator: jest.fn().mockImplementation(() => ({ + configure: jest.fn(), + start: jest.fn(), + stop: jest.fn(), + runOnce: jest.fn(), + })), +})) + +jest.mock('react-native-keyboard-controller', () => { + const { ScrollView, View } = jest.requireActual('react-native') + return { + KeyboardProvider: ({ children }) => children, + KeyboardAwareScrollView: ScrollView, + KeyboardAvoidingView: View, + } +}) + +// Mock Keyboard to fix KeyboardAvoidingView cleanup issues in tests +// React Native 0.81+ exports Keyboard as .default +const mockKeyboard = { + addListener: jest.fn(() => ({ remove: jest.fn() })), + removeListener: jest.fn(), + dismiss: jest.fn(), + scheduleLayoutAnimation: jest.fn(), + isVisible: jest.fn(() => false), + metrics: jest.fn(() => null), +} +jest.mock('react-native/Libraries/Components/Keyboard/Keyboard', () => ({ + default: mockKeyboard, + ...mockKeyboard, +})) + +// Mock BackHandler to return subscription with remove() method +// This covers the new subscription-based API used in React Native 0.81+ +const mockBackHandler = { + addEventListener: jest.fn(() => ({ remove: jest.fn() })), + removeEventListener: jest.fn(), + exitApp: jest.fn(), +} +jest.mock('react-native/Libraries/Utilities/BackHandler', () => ({ + default: mockBackHandler, + ...mockBackHandler, +})) diff --git a/app/package.json b/app/package.json index 5dbcba6..ddc1af8 100644 --- a/app/package.json +++ b/app/package.json @@ -35,58 +35,57 @@ "prettier:fix": "prettier --loglevel=warn --write '**/*.+(js|jsx|json|ts|tsx|md|yml|yaml)'", "pre-commit-lint": "yarn lint-staged", "typecheck": "tsc --noEmit", - "storybook": "start-storybook -p 7007", - "build-storybook": "build-storybook", "ios:setup": "bundle install && cd ios && bundle exec pod install", "android:setup": "cd android && ./gradlew app:dependencies --write-locks", "setup": "yarn ios:setup && yarn android:setup" }, "dependencies": { - "@bifold/core": "2.7.4", - "@bifold/oca": "2.7.4", - "@bifold/react-native-attestation": "2.7.4", - "@bifold/remote-logs": "2.7.4", - "@bifold/verifier": "2.7.4", - "@bifold/vrc-contexts": "0.0.1", + "@animo-id/expo-secure-environment": "0.1.5", + "@bifold/core": "3.0.16", + "@bifold/oca": "3.0.16", + "@bifold/react-hooks": "3.0.16", + "@bifold/react-native-attestation": "3.0.16", + "@bifold/remote-logs": "3.0.16", + "@bifold/verifier": "3.0.16", + "@bifold/vrc-contexts": "0.1.0-alpha.1", "@craftzdog/react-native-buffer": "^6.1.1", - "@credo-ts/anoncreds": "0.5.17", - "@credo-ts/askar": "0.5.17", - "@credo-ts/core": "0.5.17", - "@credo-ts/drpc": "0.5.17", - "@credo-ts/indy-sdk-to-askar-migration": "0.5.17", - "@credo-ts/indy-vdr": "0.5.17", - "@credo-ts/openid4vc": "0.5.17", - "@credo-ts/push-notifications": "0.7.0", - "@credo-ts/question-answer": "0.5.17", - "@credo-ts/react-hooks": "0.6.1", - "@credo-ts/react-native": "0.5.17", - "@credo-ts/webvh": "0.5.17", - "@formatjs/intl-datetimeformat": "~4.2.6", - "@formatjs/intl-displaynames": "~5.2.6", - "@formatjs/intl-getcanonicallocales": "~1.7.3", - "@formatjs/intl-listformat": "~6.3.6", - "@formatjs/intl-locale": "~2.4.47", - "@formatjs/intl-numberformat": "~7.2.6", - "@formatjs/intl-pluralrules": "~4.1.6", - "@formatjs/intl-relativetimeformat": "~9.3.3", - "@hyperledger/anoncreds-react-native": "patch:@hyperledger/anoncreds-react-native@npm%3A0.2.4#~/.yarn/patches/@hyperledger-anoncreds-react-native-npm-0.2.4-644cafe308.patch", - "@hyperledger/aries-askar-react-native": "patch:@hyperledger/aries-askar-react-native@npm%3A0.2.3#~/.yarn/patches/@hyperledger-aries-askar-react-native-npm-0.2.3-3207b51eab.patch", - "@hyperledger/indy-vdr-react-native": "patch:@hyperledger/indy-vdr-react-native@npm%3A0.2.2#~/.yarn/patches/@hyperledger-indy-vdr-react-native-npm-0.2.2-627d424b96.patch", - "@hyperledger/indy-vdr-shared": "0.2.2", + "@credo-ts/anoncreds": "0.6.3", + "@credo-ts/askar": "0.6.3", + "@credo-ts/core": "0.6.3", + "@credo-ts/didcomm": "0.6.3", + "@credo-ts/indy-vdr": "0.6.3", + "@credo-ts/openid4vc": "0.6.3", + "@credo-ts/question-answer": "0.6.3", + "@credo-ts/react-native": "0.6.3", + "@credo-ts/webvh": "0.6.3", + "@formatjs/intl-datetimeformat": "~6.18.2", + "@formatjs/intl-displaynames": "~6.8.13", + "@formatjs/intl-getcanonicallocales": "~2.5.6", + "@formatjs/intl-listformat": "~7.7.13", + "@formatjs/intl-locale": "~4.2.13", + "@formatjs/intl-numberformat": "~8.15.6", + "@formatjs/intl-pluralrules": "~5.4.6", + "@formatjs/intl-relativetimeformat": "~11.4.13", + "@hyperledger/anoncreds-react-native": "0.3.4", + "@hyperledger/indy-vdr-react-native": "0.2.4", + "@hyperledger/indy-vdr-shared": "0.2.3", + "@openwallet-foundation/askar-react-native": "0.6.0", "@pexip/infinity-api": "~19.1.2", - "@react-native-async-storage/async-storage": "~1.22.3", + "@react-native-async-storage/async-storage": "~2.2.0", "@react-native-clipboard/clipboard": "~1.16.3", - "@react-native-community/netinfo": "~11.3.3", + "@react-native-community/netinfo": "~11.4.1", "@react-native-firebase/app": "~21.14.0", "@react-native-firebase/messaging": "~21.14.0", "@react-navigation/bottom-tabs": "~6.0.9", "@react-navigation/devtools": "~6.0.27", "@react-navigation/native": "~6.0.16", "@react-navigation/stack": "~6.3.29", - "axios": "~1.4.0", + "axios": "~1.13.2", "base-64": "~1.0.0", "buffer": "^6.0.3", - "credo-ts-indy-vdr-proxy-client": "0.2.4", + "expo": "~54.0.31", + "expo-crypto": "~15.0.8", + "expo-secure-store": "~15.0.8", "fast-text-encoding": "~1.0.6", "i18next": "~21.6.16", "js-sha256": "^0.11.1", @@ -96,9 +95,9 @@ "lodash.startcase": "~4.4.0", "moment": "~2.29.4", "query-string": "~7.1.3", - "react": "~18.3.1", + "react": "19.1.0", "react-i18next": "~11.17.1", - "react-native": "0.77.3", + "react-native": "0.81.5", "react-native-animated-pagination-dots": "~0.1.73", "react-native-argon2": "~2.0.1", "react-native-bouncy-checkbox": "~3.0.7", @@ -111,33 +110,36 @@ "react-native-document-picker": "^9.3.1", "react-native-encrypted-storage": "~4.0.3", "react-native-fs": "~2.20.0", - "react-native-gesture-handler": "~2.22.0", + "react-native-gesture-handler": "~2.28.0", "react-native-get-random-values": "~1.11.0", - "react-native-gifted-chat": "*", + "react-native-gifted-chat": "~3.3.2", "react-native-inappbrowser-reborn": "~3.7.0", "react-native-incall-manager": "~4.2.1", - "react-native-keychain": "~8.1.3", + "react-native-keyboard-controller": "~1.18.5", + "react-native-keychain": "~10.0.0", "react-native-linear-gradient": "^2.8.3", "react-native-localize": "~2.2.6", "react-native-logs": "~5.1.0", "react-native-orientation-locker": "~1.6.0", "react-native-permissions": "~5.4.1", "react-native-qrcode-svg": "~6.2.0", - "react-native-safe-area-context": "~5.1.0", + "react-native-reanimated": "~3.19.5", + "react-native-safe-area-context": "~5.6.2", "react-native-scalable-image": "~1.1.0", "react-native-screenguard": "~1.1.0", - "react-native-screens": "~4.6.0", + "react-native-screens": "~4.16.0", "react-native-splash-screen": "~3.3.0", - "react-native-svg": "~15.11.1", + "react-native-svg": "~15.12.1", "react-native-tcp-socket": "~6.0.6", "react-native-toast-message": "~2.1.10", + "react-native-url-polyfill": "3.0.0", "react-native-uuid": "~2.0.3", - "react-native-vector-icons": "~10.0.3", + "react-native-vector-icons": "~10.3.0", "react-native-video": "~6.16.1", "react-native-vision-camera": "4.7.3", "react-native-volume-manager": "~1.10.0", "react-native-webrtc": "~124.0.6", - "react-native-webview": "~13.13.1", + "react-native-webview": "~13.15.0", "react-native-zeroconf": "~0.14.0", "readable-stream": "^4.7.0", "reflect-metadata": "~0.1.14", @@ -147,26 +149,20 @@ "uuid": "~9.0.1" }, "devDependencies": { - "@babel/core": "~7.25.2", - "@babel/preset-env": "~7.25.3", - "@babel/runtime": "~7.25.0", + "@babel/core": "~7.28.6", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/preset-env": "~7.28.6", + "@babel/runtime": "~7.28.6", "@commitlint/cli": "~11.0.0", "@eslint/js": "~8.57.1", - "@react-native-community/cli": "15.0.1", - "@react-native-community/cli-platform-android": "15.0.1", - "@react-native-community/cli-platform-ios": "15.0.1", - "@react-native/babel-preset": "0.77.3", - "@react-native/eslint-config": "0.77.3", - "@react-native/eslint-plugin": "0.77.3", - "@react-native/metro-config": "0.77.3", - "@react-native/typescript-config": "0.77.3", - "@storybook/addon-actions": "~5.3.21", - "@storybook/addon-knobs": "~5.3.21", - "@storybook/addon-links": "~5.3.21", - "@storybook/addon-ondevice-actions": "~5.3.23", - "@storybook/addon-ondevice-knobs": "~5.3.26", - "@storybook/react-native": "~5.3.27", - "@storybook/react-native-server": "~5.3.23", + "@react-native-community/cli": "20.0.2", + "@react-native-community/cli-platform-android": "20.0.2", + "@react-native-community/cli-platform-ios": "20.0.2", + "@react-native/babel-preset": "0.81.5", + "@react-native/eslint-config": "0.81.5", + "@react-native/eslint-plugin": "0.81.5", + "@react-native/metro-config": "0.81.5", + "@react-native/typescript-config": "0.81.5", "@testing-library/jest-native": "~5.4.3", "@testing-library/react-native": "~12.3.3", "@types/eslint__js": "~8.42.3", @@ -174,14 +170,13 @@ "@types/lodash.flatten": "~4.4.9", "@types/lodash.merge": "~4.6.9", "@types/lodash.startcase": "~4.4.9", - "@types/react": "~18.2.79", - "@types/react-native": "~0.71.13", + "@types/react": "~19.1.9", "@types/react-native-vector-icons": "~6.4.18", - "@types/react-test-renderer": "~18.0.7", + "@types/react-test-renderer": "~19.1.0", "@types/readable-stream": "^4", "@typescript-eslint/eslint-plugin": "~7.18.0", "@typescript-eslint/parser": "~7.18.0", - "babel-jest": "~27.5.1", + "babel-jest": "~29.7.0", "babel-plugin-module-resolver": "~5.0.2", "commitlint": "~17.7.2", "copyfiles": "~2.4.1", @@ -195,16 +190,15 @@ "husky": "~7.0.4", "jest": "~29.6.4", "lint-staged": "~11.2.6", - "metro-react-native-babel-transformer": "~0.77.0", "mockdate": "~3.0.5", "patch-package": "^8.0.1", "pod-install": "~0.1.39", "postinstall-postinstall": "^2.1.0", "prettier": "~2.8.8", - "react-dom": "~18.3.1", + "react-dom": "19.1.0", "react-native-svg-transformer": "~0.14.3", - "react-test-renderer": "~18.3.1", - "typescript": "~5.5.4", + "react-test-renderer": "19.1.0", + "typescript": "~5.9.2", "typescript-eslint": "~7.18.0" } } diff --git a/app/src/hooks/notifications.ts b/app/src/hooks/notifications.ts index f0e1b81..baf2232 100644 --- a/app/src/hooks/notifications.ts +++ b/app/src/hooks/notifications.ts @@ -1,12 +1,6 @@ -import { AnonCredsCredentialMetadataKey } from '@credo-ts/anoncreds/build/utils/metadata' -import { - BasicMessageRecord, - CredentialExchangeRecord as CredentialRecord, - CredentialState, - ProofExchangeRecord, - ProofState, -} from '@credo-ts/core' -import { useCredentialByState, useProofByState, useBasicMessages, useAgent } from '@credo-ts/react-hooks' +import { AnonCredsCredentialMetadataKey } from '@credo-ts/anoncreds' +import { DidCommBasicMessageRecord, DidCommCredentialExchangeRecord, DidCommCredentialState, DidCommProofExchangeRecord, DidCommProofState } from '@credo-ts/didcomm' +import { useCredentialByState, useProofByState, useBasicMessages, useAgent } from '@bifold/react-hooks' import { BifoldAgent, useStore, @@ -32,22 +26,22 @@ function isProtocolMessage(content: string): boolean { } } -export const useNotifications = (): Array => { +export const useNotifications = (): Array => { const { agent } = useAgent() const [store] = useStore() - const offers = useCredentialByState(CredentialState.OfferReceived) - const proofsRequested = useProofByState(ProofState.RequestReceived) - const [nonAttestationProofs, setNonAttestationProofs] = useState([]) + const offers = useCredentialByState(DidCommCredentialState.OfferReceived) + const proofsRequested = useProofByState(DidCommProofState.RequestReceived) + const [nonAttestationProofs, setNonAttestationProofs] = useState([]) const [notifications, setNotifications] = useState([]) const { records: basicMessages } = useBasicMessages() - const credsReceived = useCredentialByState(CredentialState.CredentialReceived) - const credsDone = useCredentialByState(CredentialState.Done) - const proofsDone = useProofByState([ProofState.Done, ProofState.PresentationReceived]) + const credsReceived = useCredentialByState(DidCommCredentialState.CredentialReceived) + const credsDone = useCredentialByState(DidCommCredentialState.Done) + const proofsDone = useProofByState([DidCommProofState.Done, DidCommProofState.PresentationReceived]) useEffect(() => { // get all unseen messages, excluding protocol/witness messages - const unseenMessages: BasicMessageRecord[] = basicMessages.filter((msg) => { + const unseenMessages: DidCommBasicMessageRecord[] = basicMessages.filter((msg) => { if (isProtocolMessage(msg.content)) return false const meta = msg.metadata.get(BasicMessageMetadata.customMetadata) as basicMessageCustomMetadata return !meta?.seen @@ -55,7 +49,7 @@ export const useNotifications = (): Array { if (!contactsWithUnseenMessages.includes(msg.connectionId)) { contactsWithUnseenMessages.push(msg.connectionId) @@ -63,7 +57,7 @@ export const useNotifications = (): Array { + const revoked = credsDone.filter((cred: DidCommCredentialExchangeRecord) => { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const metadata = cred!.metadata.get(CredentialMetadata.customMetadata) as credentialCustomMetadata if (cred?.revocationNotification && metadata?.revoked_seen == undefined) { @@ -85,7 +79,7 @@ export const useNotifications = (): Array { return ( - ![ProofState.Done, ProofState.PresentationReceived].includes(proof.state) || + ![DidCommProofState.Done, DidCommProofState.PresentationReceived].includes(proof.state) || (proof.isVerified !== undefined && !(proof.metadata.data[ProofMetadata.customMetadata] as ProofCustomMetadata)?.details_seen) ) @@ -107,7 +101,7 @@ export const useNotifications = (): Array { Promise.all( - [...proofsRequested, ...proofsDone].map(async (proof: ProofExchangeRecord) => { + [...proofsRequested, ...proofsDone].map(async (proof: DidCommProofExchangeRecord) => { const isAttestation = await isProofRequestingAttestation(proof, agent as BifoldAgent, AttestationRestrictions) return { value: proof, diff --git a/app/src/hooks/useBCAgentSetup.ts b/app/src/hooks/useBCAgentSetup.ts index ee15300..70adc43 100644 --- a/app/src/hooks/useBCAgentSetup.ts +++ b/app/src/hooks/useBCAgentSetup.ts @@ -9,8 +9,9 @@ import { WalletSecret, setupVrcConnectionHandler, } from '@bifold/core' -import { Agent, HttpOutboundTransport, MediatorPickupStrategy, WsOutboundTransport } from '@credo-ts/core' -import { IndyVdrPoolConfig, IndyVdrPoolService } from '@credo-ts/indy-vdr/build/pool' +import { Agent } from '@credo-ts/core' +import { DidCommHttpOutboundTransport, DidCommMediatorPickupStrategy, DidCommWsOutboundTransport } from '@credo-ts/didcomm' +import { IndyVdrPoolConfig, IndyVdrPoolService } from '@credo-ts/indy-vdr' import { agentDependencies } from '@credo-ts/react-native' import { GetCredentialDefinitionRequest, GetSchemaRequest } from '@hyperledger/indy-vdr-shared' import moment from 'moment' @@ -36,7 +37,7 @@ const loadCachedLedgers = async (): Promise => const configureMessagePickup = async (agent: Agent): Promise => { if (Config.MEDIATOR_USE_V2_BATCH_PICKUP === 'true') { - await agent.mediationRecipient.initiateMessagePickup(undefined, MediatorPickupStrategy.PickUpV2LiveMode) + await agent.modules.didcomm.mediationRecipient.initiateMessagePickup(undefined, DidCommMediatorPickupStrategy.PickUpV2LiveMode) batchPickup(agent) } } @@ -63,12 +64,10 @@ const useBCAgentSetup = () => { ) const restartExistingAgent = useCallback( - async (agent: Agent, walletSecret: WalletSecret): Promise => { + async (agent: Agent): Promise => { try { - await agent.wallet.open({ - id: walletSecret.id, - key: walletSecret.key, - }) + // credo 0.6: the askar store config (id/key) lives on the AskarModule, + // so re-initializing reopens the wallet await agent.initialize() } catch (error) { logger.warn(`Agent restart failed with error ${error}`) @@ -86,19 +85,15 @@ const useBCAgentSetup = () => { async (ledgers: IndyVdrPoolConfig[], walletSecret: WalletSecret, mediatorUrl: string): Promise => { const options = { config: { - label: store.preferences.walletName || 'Keyring', - walletConfig: { - id: walletSecret.id, - key: walletSecret.key, - }, logger, - mediatorPickupStrategy: MediatorPickupStrategy.Implicit, autoUpdateStorageOnStartup: true, - autoAcceptConnections: true, + // credo 0.6: wallet id/key live on the AskarModule store config, + // mediation + auto-accept live on the DidCommModule (see bc-agent-modules.ts) // Document loader is configured in W3cCredentialsModule (see bc-agent-modules.ts) }, dependencies: agentDependencies, modules: getBCAgentModules({ + walletSecret, indyNetworks: ledgers, mediatorInvitationUrl: mediatorUrl, txnCache: { @@ -106,27 +101,19 @@ const useBCAgentSetup = () => { expiryOffsetMs: 1000 * 60 * 60 * 24 * 7, path: CachesDirectoryPath + '/txn-cache', }, - enableProxy: store.developer.enableProxy, - proxyBaseUrl: Config.INDY_VDR_PROXY_URL, - proxyCacheSettings: { - allowCaching: false, - cacheDurationInSeconds: 60 * 60 * 24 * 7, - }, }), } - logger.info(store.developer.enableProxy && Config.INDY_VDR_PROXY_URL ? 'VDR Proxy enabled' : 'VDR Proxy disabled') - const newAgent = new Agent(options) - const wsTransport = new WsOutboundTransport() - const httpTransport = new HttpOutboundTransport() + const wsTransport = new DidCommWsOutboundTransport() + const httpTransport = new DidCommHttpOutboundTransport() - newAgent.registerOutboundTransport(wsTransport) - newAgent.registerOutboundTransport(httpTransport) + newAgent.modules.didcomm.registerOutboundTransport(wsTransport) + newAgent.modules.didcomm.registerOutboundTransport(httpTransport) return newAgent }, - [store.preferences.walletName, logger, store.developer.enableProxy] + [logger] ) const migrateIfRequired = useCallback( @@ -145,8 +132,11 @@ const useBCAgentSetup = () => { const warmUpCache = useCallback( async (newAgent: Agent, cachedLedgers?: IndyVdrPoolConfig[]) => { const poolService = newAgent.dependencyManager.resolve(IndyVdrPoolService) - if (!cachedLedgers) { - // these escapes can be removed once Indy VDR has been upgraded and the patch is no longer needed + // refreshPoolConnections/getAllPoolTransactions came from the BC indy-vdr + // patch (credo 0.5); the unpatched 0.6.3 pool service does not have them + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore:next-line + if (!cachedLedgers && typeof poolService.refreshPoolConnections === 'function') { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore:next-line await poolService.refreshPoolConnections() @@ -194,7 +184,7 @@ const useBCAgentSetup = () => { const mediatorUrl = store.preferences.selectedMediator logger.info('Checking for existing agent...') if (agentInstanceRef.current) { - const restartedAgent = await restartExistingAgent(agentInstanceRef.current, walletSecret) + const restartedAgent = await restartExistingAgent(agentInstanceRef.current) if (restartedAgent) { logger.info('Successfully restarted existing agent...') await configureMessagePickup(restartedAgent) diff --git a/app/src/keyring-theme/components/AddCredentialSlider.tsx b/app/src/keyring-theme/components/AddCredentialSlider.tsx index b166dec..0216565 100644 --- a/app/src/keyring-theme/components/AddCredentialSlider.tsx +++ b/app/src/keyring-theme/components/AddCredentialSlider.tsx @@ -1,7 +1,7 @@ import { SafeAreaModal, Screens, Stacks, testIdForAccessabilityLabel, testIdWithKey } from '@bifold/core' -import { AnonCredsCredentialMetadataKey } from '@credo-ts/anoncreds/build/utils/metadata' -import { CredentialState } from '@credo-ts/core' -import { useCredentialByState } from '@credo-ts/react-hooks' +import { AnonCredsCredentialMetadataKey } from '@credo-ts/anoncreds' +import { DidCommCredentialState } from '@credo-ts/didcomm' +import { useCredentialByState } from '@bifold/react-hooks' import { useNavigation } from '@react-navigation/native' import React, { useCallback, useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -21,8 +21,8 @@ export default function AddCredentialSlider() { const [addCredentialPressed, setAddCredentialPressed] = useState(false) const [showGetPersonCredential, setShowGetPersonCredential] = useState(false) - const credentialsReceived = useCredentialByState(CredentialState.CredentialReceived) - const credentialsDone = useCredentialByState(CredentialState.Done) + const credentialsReceived = useCredentialByState(DidCommCredentialState.CredentialReceived) + const credentialsDone = useCredentialByState(DidCommCredentialState.Done) const deactivateSlider = useCallback(() => { DeviceEventEmitter.emit(KeyRingEventTypes.ADD_CREDENTIAL_PRESSED, false) diff --git a/app/src/keyring-theme/components/HomeHeaderView.tsx b/app/src/keyring-theme/components/HomeHeaderView.tsx index 2a1c2c5..396f2e0 100644 --- a/app/src/keyring-theme/components/HomeHeaderView.tsx +++ b/app/src/keyring-theme/components/HomeHeaderView.tsx @@ -1,4 +1,4 @@ -import { useAgent } from '@credo-ts/react-hooks' +import { useAgent } from '@bifold/react-hooks' import { Screens, Stacks, testIdWithKey, useTheme } from '@bifold/core' import { RemoteLogger } from '@bifold/remote-logs' import { useNavigation } from '@react-navigation/native' diff --git a/app/src/keyring-theme/features/person-flow/screens/PersonCredential.tsx b/app/src/keyring-theme/features/person-flow/screens/PersonCredential.tsx index e6ce940..c3574b9 100644 --- a/app/src/keyring-theme/features/person-flow/screens/PersonCredential.tsx +++ b/app/src/keyring-theme/features/person-flow/screens/PersonCredential.tsx @@ -1,4 +1,4 @@ -import { useAgent } from '@credo-ts/react-hooks' +import { useAgent } from '@bifold/react-hooks' import { useStore, useTheme, diff --git a/app/src/keyring-theme/features/person-flow/screens/PersonCredentialLoading.tsx b/app/src/keyring-theme/features/person-flow/screens/PersonCredentialLoading.tsx index 61a319f..ce6af6e 100644 --- a/app/src/keyring-theme/features/person-flow/screens/PersonCredentialLoading.tsx +++ b/app/src/keyring-theme/features/person-flow/screens/PersonCredentialLoading.tsx @@ -14,8 +14,8 @@ import { useStore, useTheme, } from '@bifold/core' -import { CredentialState } from '@credo-ts/core' -import { useAgent, useCredentialByState } from '@credo-ts/react-hooks' +import { DidCommCredentialState } from '@credo-ts/didcomm' +import { useAgent, useCredentialByState } from '@bifold/react-hooks' import { StackScreenProps } from '@react-navigation/stack' import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -38,9 +38,9 @@ const PersonCredentialLoading: React.FC = ({ navigation }) => { const { ColorPalette, TextTheme, Spacing } = useTheme() const [store] = useStore() const [remoteAgentDetails, setRemoteAgentDetails] = useState() - const timer = useRef() + const timer = useRef(undefined) const [logger] = useServices([TOKENS.UTIL_LOGGER]) - const receivedCredentialOffers = useCredentialByState(CredentialState.OfferReceived) + const receivedCredentialOffers = useCredentialByState(DidCommCredentialState.OfferReceived) const [stepText, setStepText] = useState('Starting process...') const [progressPercent, setProgressPercent] = useState(0) const { agent } = useAgent() @@ -224,7 +224,7 @@ const PersonCredentialLoading: React.FC = ({ navigation }) => { useEffect(() => { for (const credential of receivedCredentialOffers) { if ( - credential.state == CredentialState.OfferReceived && + credential.state == DidCommCredentialState.OfferReceived && credential.connectionId === remoteAgentDetails?.connectionId ) { goToCredentialOffer(credential.id) diff --git a/app/src/keyring-theme/features/person-flow/utils/BCIDHelper.ts b/app/src/keyring-theme/features/person-flow/utils/BCIDHelper.ts index af5676d..37a3328 100644 --- a/app/src/keyring-theme/features/person-flow/utils/BCIDHelper.ts +++ b/app/src/keyring-theme/features/person-flow/utils/BCIDHelper.ts @@ -52,7 +52,7 @@ export const connectToIASAgent = async ( ): Promise => { // connect to the agent, this will re-format the legacy invite // until we have OOB working in ACA-py. - const invite = await agent.oob.parseInvitation(iasAgentInviteUrl) + const invite = await agent.modules.didcomm.oob.parseInvitation(iasAgentInviteUrl) if (!invite) { throw new BifoldError(t('Error.Title2020'), t('Error.Message2020'), t('Error.NoMessage'), ErrorCodes.BadInvitation) @@ -60,7 +60,7 @@ export const connectToIASAgent = async ( await removeExistingInvitationsById(agent, invite.id) - const record = await agent.oob.receiveInvitation(invite) + const record = await agent.modules.didcomm.oob.receiveInvitation(invite) if (!record) { throw new BifoldError( diff --git a/app/src/keyring-theme/theme.ts b/app/src/keyring-theme/theme.ts index 3daa88b..54b7eea 100644 --- a/app/src/keyring-theme/theme.ts +++ b/app/src/keyring-theme/theme.ts @@ -158,6 +158,13 @@ export const BrandColors: IBrandColors = { tabBarInactive: MEDIUM_GRAY, // #666666 inlineError: SemanticColors.error, inlineWarning: NotificationColors.warnText, + // New in bifold 3.x IBrandColors + credentialCardPlaceholderBackground: GrayscaleColors.veryLightGrey, + credentialCardStatusBadgeErrorBackground: '#FDECEA', + credentialCardStatusBadgeErrorIcon: BKC_BLACK, + credentialCardStatusBadgeWarningBackground: '#FFF8E1', + credentialCardStatusBadgeWarningIcon: BKC_BLACK, + loadingIcon: GrayscaleColors.white, } export const ColorPalette: IColorPalette = { diff --git a/app/src/screens/Developer.tsx b/app/src/screens/Developer.tsx index f6fa961..999f213 100644 --- a/app/src/screens/Developer.tsx +++ b/app/src/screens/Developer.tsx @@ -11,7 +11,7 @@ import { clearTestContacts, } from '@bifold/core' import { RemoteLogger, RemoteLoggerEventTypes } from '@bifold/remote-logs' -import { useAgent } from '@credo-ts/react-hooks' +import { useAgent } from '@bifold/react-hooks' import { useNavigation } from '@react-navigation/native' import React, { useState } from 'react' import { useTranslation } from 'react-i18next' @@ -106,7 +106,7 @@ const Developer: React.FC = () => { setEnvironmentModalVisible(false) } - const SectionHeader = ({ icon, title }: { icon: string; title: string }): JSX.Element => ( + const SectionHeader = ({ icon, title }: { icon: string; title: string }): React.JSX.Element => ( {title} @@ -117,9 +117,9 @@ const Developer: React.FC = () => { title: string accessibilityLabel?: string testID?: string - children: JSX.Element + children: React.JSX.Element showRowSeparator?: boolean - subContent?: JSX.Element + subContent?: React.JSX.Element onPress?: () => void } const SectionRow = ({ diff --git a/app/src/services/attestation.ts b/app/src/services/attestation.ts index 97c7e90..b2804a9 100644 --- a/app/src/services/attestation.ts +++ b/app/src/services/attestation.ts @@ -4,34 +4,20 @@ import { AttestationMonitor as AttestationMonitorI, BifoldAgent, BifoldError, - removeExistingInvitationsById, } from '@bifold/core' +import { Agent, BaseEvent } from '@credo-ts/core' import { - appleAttestation, - generateKey, - googleAttestation, - isPlayIntegrityAvailable, -} from '@bifold/react-native-attestation' -import { AnonCredsCredentialOffer } from '@credo-ts/anoncreds' -import { - Agent, - BaseEvent, - ConnectionRecord, - CredentialEventTypes, - CredentialExchangeRecord, - CredentialState, - ProofEventTypes, - ProofExchangeRecord, - ProofState, -} from '@credo-ts/core' -import { DeviceEventEmitter, Platform } from 'react-native' -import { getBuildNumber, getSystemName, getSystemVersion, getVersion } from 'react-native-device-info' + DidCommCredentialEventTypes, + DidCommCredentialExchangeRecord, + DidCommCredentialState, + DidCommProofEventTypes, + DidCommProofExchangeRecord, + DidCommProofState, +} from '@credo-ts/didcomm' +import { DeviceEventEmitter } from 'react-native' import { AttestationRestrictions } from '@/constants' import { credentialsMatchForProof } from '@utils/credentials' -import { AttestationRequestParams, AttestationResult, requestAttestationDrpc, requestNonceDrpc } from '@utils/drpc' - -const defaultResponseTimeoutInMs = 10000 // DRPC response timeout // subscription type from agent events (TODO: add type export from Credo) type AgentSubscription = ReturnType['subscribe']> @@ -100,11 +86,11 @@ const findCredDefIDs = (restrictions: [Restriction]): Array => { } const invitationUrlFromRestrictions = async ( - proof: ProofExchangeRecord, + proof: DidCommProofExchangeRecord, agent: BifoldAgent, restrictions: AttestationRestrictionsType ): Promise => { - const format = (await agent.proofs.getFormatData(proof.id)) as unknown as AttestationProofRequestFormat + const format = (await agent.modules.didcomm.proofs.getFormatData(proof.id)) as unknown as AttestationProofRequestFormat const formatToUse = format.request?.anoncreds ? 'anoncreds' : 'indy' const restrictionsArePresent = format.request?.[formatToUse]?.requested_attributes?.attestationInfo?.restrictions @@ -127,7 +113,7 @@ const invitationUrlFromRestrictions = async ( } export const isProofRequestingAttestation = async ( - proof: ProofExchangeRecord, + proof: DidCommProofExchangeRecord, agent: BifoldAgent, restrictions: AttestationRestrictionsType ): Promise => { @@ -156,7 +142,7 @@ export class AttestationMonitor implements AttestationMonitorI { private log?: AbstractBifoldLogger private _attestationWorkflowInProgress = false private _shouldHandleProofRequestAutomatically = false - private _proofRequest?: ProofExchangeRecord + private _proofRequest?: DidCommProofExchangeRecord // private _currentWorkflowState?: typeof AttestationEventTypes // take in options, agent, and logger. Options should include the attestation service URL @@ -184,11 +170,11 @@ export class AttestationMonitor implements AttestationMonitorI { this.agent = agent this.proofSubscription = this.agent?.events - .observable(ProofEventTypes.ProofStateChanged) + .observable(DidCommProofEventTypes.ProofStateChanged) .subscribe(this.handleProofStateChanged) this.offerSubscription = this.agent?.events - .observable(CredentialEventTypes.CredentialStateChanged) + .observable(DidCommCredentialEventTypes.DidCommCredentialStateChanged) .subscribe(this.handleCredentialStateChanged) } @@ -198,74 +184,21 @@ export class AttestationMonitor implements AttestationMonitorI { } public requestAttestationCredential = async (): Promise => { - if (!this.agent || !this._proofRequest) { - throw new BifoldError( + // The BC Wallet implementation fetched a fresh attestation credential from + // BC's attestation service over DRPC. Keyring does not run that service + // (and @credo-ts/drpc has no stable credo 0.6 release), so we surface a + // failure event instead. Keyring hardware attestation for VRC lives in + // @bifold/react-native-attestation and the VRC module. + this.log?.warn('Remote attestation credential issuance is not available in Keyring') + this.stopWorkflow( + AttestationEventTypes.FailedRequestCredential, + new BifoldError( 'Attestation Service', - 'There was a problem with the remote attestation service.', - 'The agent cannot be undefined.', - AttestationErrorCodes.FailedToFetchNonceForAttestation + 'Remote attestation credential issuance is not available.', + 'This wallet does not use the BC attestation service.', + AttestationErrorCodes.FailedToRequestAttestation ) - } - - this.log?.info('Fetching attestation credential') - - this.startWorkflow() - - try { - const invitationUrl = await invitationUrlFromRestrictions(this._proofRequest, this.agent, AttestationRestrictions) - if (!invitationUrl) { - throw new BifoldError( - 'Attestation Service', - 'Unable to connect to the attestation service.', - 'No details provided.', - AttestationErrorCodes.FailedToConnectToAttestationAgent - ) - } - - const connection = await this.connectToAttestationAgent(invitationUrl) - if (!connection) { - throw new BifoldError( - 'Attestation Service', - 'Unable to connect to the attestation service.', - 'No details provided.', - AttestationErrorCodes.FailedToConnectToAttestationAgent - ) - } - - const nonce = await this.fetchNonceForAttestation(connection) - if (!nonce) { - throw new BifoldError( - 'Attestation Service', - 'There was a problem with the attestation service.', - 'No details provided.', - AttestationErrorCodes.FailedToFetchNonceForAttestation - ) - } - - const attestationObj = await this.generateAttestation(nonce) - if (!attestationObj) { - throw new BifoldError( - 'Attestation Service', - 'There was a problem with the attestation service.', - 'No details provided.', - AttestationErrorCodes.FailedToGenerateAttestation - ) - } - - const result = await this.requestAttestation(connection, attestationObj) - if (result.status !== 'success') { - throw new BifoldError( - 'Attestation Service', - 'There was a problem with the attestation service.', - 'No details provided.', - AttestationErrorCodes.FailedToValidateAttestation - ) - } - } catch (error) { - this.log?.error('Failed to fetch attestation credential', error as Error) - - this.stopWorkflow(AttestationEventTypes.FailedRequestCredential, error as Error) - } + ) } private startWorkflow = () => { @@ -279,20 +212,20 @@ export class AttestationMonitor implements AttestationMonitorI { DeviceEventEmitter.emit(eventType, error) } - private handleProofRequest = async (proofRequest: ProofExchangeRecord): Promise => { + private handleProofRequest = async (proofRequest: DidCommProofExchangeRecord): Promise => { if (!this.agent) { return false } this.log?.info('Selecting credentials for attestation proof request') // This will throw if we don't have the necessary credentials - const credentials = await this.agent.proofs.selectCredentialsForRequest({ - proofRecordId: proofRequest.id, + const credentials = await this.agent.modules.didcomm.proofs.selectCredentialsForRequest({ + proofExchangeRecordId: proofRequest.id, }) this.log?.info('Accepting attestation proof request') - await this.agent.proofs.acceptRequest({ - proofRecordId: proofRequest.id, + await this.agent.modules.didcomm.proofs.acceptRequest({ + proofExchangeRecordId: proofRequest.id, proofFormats: credentials.proofFormats, }) @@ -310,13 +243,13 @@ export class AttestationMonitor implements AttestationMonitorI { } const { credentialRecord } = event.payload - const credential = credentialRecord as CredentialExchangeRecord + const credential = credentialRecord as DidCommCredentialExchangeRecord this.log?.info('Handling credential offer') try { - const { offer } = await this.agent.credentials.getFormatData(credential.id) - const offerData = (offer?.anoncreds ?? offer?.indy) as AnonCredsCredentialOffer + const { offer } = await this.agent.modules.didcomm.credentials.getFormatData(credential.id) + const offerData = (offer?.anoncreds ?? offer?.indy) as { cred_def_id?: string } | undefined // do nothing if not an attestation credential const offerIsForAttestation = await isOfferingAttestation(offerData?.cred_def_id ?? '', AttestationRestrictions) @@ -325,20 +258,20 @@ export class AttestationMonitor implements AttestationMonitorI { } // if it's a new offer, automatically accept - if (credential.state === CredentialState.OfferReceived) { + if (credential.state === DidCommCredentialState.OfferReceived) { this.log?.info('Accepting credential offer') - await this.agent.credentials.acceptOffer({ - credentialRecordId: credential.id, + await this.agent.modules.didcomm.credentials.acceptOffer({ + credentialExchangeRecordId: credential.id, }) } // only finish loading state once credential is fully accepted - if (credential.state === CredentialState.Done) { + if (credential.state === DidCommCredentialState.Done) { // TODO: credential.offer in flight completed this.log?.info('Credential accepted') if (this._shouldHandleProofRequestAutomatically && this._proofRequest) { - if (this._proofRequest.state === ProofState.RequestReceived) { + if (this._proofRequest.state === DidCommProofState.RequestReceived) { const result = await this.handleProofRequest(this._proofRequest) if (result) { this.stopWorkflow(AttestationEventTypes.Completed) @@ -366,11 +299,11 @@ export class AttestationMonitor implements AttestationMonitorI { } const { proofRecord } = event.payload - const proof = proofRecord as ProofExchangeRecord + const proof = proofRecord as DidCommProofExchangeRecord this.log?.info('Handling proof received') - if (proof.state !== ProofState.RequestReceived) { + if (proof.state !== DidCommProofState.RequestReceived) { return } @@ -419,232 +352,9 @@ export class AttestationMonitor implements AttestationMonitorI { } } - private async connectToAttestationAgent(invitationUrl: string): Promise { - if (!this.agent) { - throw new BifoldError( - 'Attestation Service', - 'There was a problem with the remote attestation service.', - 'The agent cannot be undefined.', - AttestationErrorCodes.FailedToFetchNonceForAttestation - ) - } - - const invite = await this.agent.oob.parseInvitation(invitationUrl) - - if (!invite) { - this.log?.error('Unable to parse attestation agent invitation') - - throw new BifoldError( - 'Attestation Service', - 'Unable to parse the attestation agent invitation', - 'No details provided.', - AttestationErrorCodes.BadInvitation - ) - } - - this.log?.info('Removing any existing duplicate invitations if they exist') - await removeExistingInvitationsById(this.agent, invite.id) - - this.log?.info('Receiving invitation') - const { connectionRecord } = await this.agent.oob.receiveInvitation(invite) - if (!connectionRecord) { - throw new BifoldError( - 'Attestation Service', - 'Unable to accept attestation agent invitation', - 'No details provided.', - AttestationErrorCodes.BadInvitation - ) - } - - // this step will fail if there is more than one active connection record between a given wallet and - // the traction instance which is why we need to `removeExistingInvitationsById` above - return await this.agent.connections.returnWhenIsConnected(connectionRecord.id) - } - - private async fetchNonceForAttestation(connection: ConnectionRecord): Promise { - if (!this.agent) { - throw new BifoldError( - 'Attestation Service', - 'There was a problem with the remote attestation service.', - 'The agent cannot be undefined.', - AttestationErrorCodes.FailedToFetchNonceForAttestation - ) - } - - this.log?.info('Requesting nonce from controller') - - const requestNonceCb = await requestNonceDrpc(this.agent, connection) - const nonceResponse = await requestNonceCb(defaultResponseTimeoutInMs) - - if (!nonceResponse) { - this.log?.error('Failed to fetch nonce for attestation, code = none, reason = timeout occurred.') - - throw new BifoldError( - 'Attestation Service', - 'There was a problem with the remote attestation service.', - 'Timeout occurred.', - AttestationErrorCodes.FailedToFetchNonceForAttestation - ) - } - - this.log?.info('DRPC nonce response received') - - if (nonceResponse.error) { - this.log?.error( - `Failed to fetch nonce for attestation, code = ${nonceResponse.error.code}, reason = ${nonceResponse.error.message}` - ) - - throw new BifoldError( - 'Attestation Service', - 'There was a problem with the remote attestation service.', - nonceResponse.error.message ?? 'No details provided.', - AttestationErrorCodes.FailedToFetchNonceForAttestation - ) - } - - const nonce = nonceResponse.result.nonce - - return nonce - } - - private async requestAttestation( - connection: ConnectionRecord, - attestationObj: AttestationRequestParams - ): Promise { - if (!this.agent) { - throw new BifoldError( - 'Attestation Service', - 'There was a problem with the remote attestation service.', - 'No details provided.', - AttestationErrorCodes.FailedToFetchNonceForAttestation - ) - } - - this.log?.info('Requesting attestation credential from controller') - - const requestAttestationCb = await requestAttestationDrpc(this.agent, connection, attestationObj) - const attestationResponse = await requestAttestationCb(defaultResponseTimeoutInMs) - - if (!attestationResponse) { - this.log?.error('Failed to request attestation, code = none, reason = timeout occurred.') - - throw new BifoldError( - 'Attestation Service', - 'There was a problem with the remote attestation service.', - 'Timeout occurred.', - AttestationErrorCodes.FailedToRequestAttestation - ) - } - - this.log?.info('DRPC attestation response received') - - if (attestationResponse.error) { - this.log?.error( - `Failed to request attestation, code = ${attestationResponse.error.code}, reason = ${attestationResponse.error.message}` - ) - - throw new BifoldError( - 'Attestation Service', - 'There was a problem with the remote attestation service.', - attestationResponse.error.message ?? 'No details provided.', - AttestationErrorCodes.FailedToRequestAttestation - ) - } - - return attestationResponse.result - } - - private commonAttestationMessageComponent() { - const common: Partial = { - app_version: `${getVersion()}-${getBuildNumber()}`, - os_version: `${getSystemName()} ${getSystemVersion()}`, - } - - return common - } - - private async generateAttestation(nonce: string) { - switch (Platform.OS) { - case 'ios': - return this.generateAppleAttestation(nonce) - case 'android': - return this.generateGoogleAttestation(nonce) - - default: - // TODO(jl): throw unsupported platform error - break - } - } - - private async generateAppleAttestation(nonce: string) { - const common = this.commonAttestationMessageComponent() - const shouldCacheKey = false - - this.log?.info('Generating key for Apple') - const keyId = await generateKey(shouldCacheKey) - - this.log?.info('Using Apple on-device attestation') - const attestationAsBuffer = await appleAttestation(keyId, nonce) - const attestationRequest = { - ...common, - platform: 'apple', - key_id: keyId, - attestation_object: attestationAsBuffer.toString('base64'), - } as AttestationRequestParams - - this.log?.info('On-device Apple attestation complete') - - return attestationRequest - } - - private async generateGoogleAttestation(nonce: string) { - const common = this.commonAttestationMessageComponent() - - this.log?.info('Checking if Play Integrity is available') - - const available = await isPlayIntegrityAvailable() - if (!available) { - this.log?.error('Google Play Integrity is unavailable') - - const error = new BifoldError( - 'Google Play Integrity Unavailable', - 'Google Play Integrity is required for device attestation but is not available on this device.', - 'The device attestation process cannot be completed without Google Play Integrity services.', - AttestationErrorCodes.IntegrityUnavailable - ) - - throw error - } else { - this.log?.info('Google Play Integrity is available') - } - - this.log?.info('Using Google on-device attestation') - - let tokenString: string - try { - tokenString = await googleAttestation(nonce) - } catch (error) { - const bifoldError = new BifoldError( - 'Google Attestation Error', - 'There was a problem with the Google Integrity API.', - (error as Error)?.message || 'No details provided.', - AttestationErrorCodes.IntegrityUnavailable - ) - throw bifoldError - } - const attestationRequest = { - ...common, - platform: 'google', - attestation_object: tokenString, - } as AttestationRequestParams - this.log?.info('On-device Google attestation complete') - - return attestationRequest - } - private attestationCredentialRequired = async (agent: BifoldAgent, proofId: string): Promise => { agent.config.logger.info('Fetching proof by id') - const proof = await agent?.proofs.getById(proofId) + const proof = await agent?.modules.didcomm.proofs.getById(proofId) agent.config.logger.info('Second check if proof is requesting attestation') agent.config.logger.info('Checking if credentials match for proof request') diff --git a/app/src/utils/PushNotificationsHelper.ts b/app/src/utils/PushNotificationsHelper.ts index 8727a86..c3d6aaa 100644 --- a/app/src/utils/PushNotificationsHelper.ts +++ b/app/src/utils/PushNotificationsHelper.ts @@ -1,4 +1,5 @@ -import { Agent, ConnectionRecord, ConnectionType } from '@credo-ts/core' +import { Agent } from '@credo-ts/core' +import { DidCommConnectionRecord, DidCommConnectionType } from '@credo-ts/didcomm' import { PersistentStorage } from '@bifold/core' import messaging, { FirebaseMessagingTypes } from '@react-native-firebase/messaging' import { Platform } from 'react-native' @@ -68,9 +69,9 @@ const requestPermission = async (): Promise => { * Helper Functions Section */ -const getMediatorConnection = async (agent: Agent): Promise => { - const connections: ConnectionRecord[] = await agent.connections.getAll() - const mediators = connections.filter((r) => r.connectionTypes.includes(ConnectionType.Mediator)) +const getMediatorConnection = async (agent: Agent): Promise => { + const connections: DidCommConnectionRecord[] = await agent.modules.didcomm.connections.getAll() + const mediators = connections.filter((r) => r.connectionTypes.includes(DidCommConnectionType.Mediator)) if (mediators.length < 1) { agent.config.logger.warn(`Mediator connection not found`) return undefined @@ -117,7 +118,7 @@ const isMediatorCapable = async (agent: Agent): Promise => const mediator = await getMediatorConnection(agent) if (!mediator) return - const response = await agent.discovery.queryFeatures({ + const response = await agent.modules.didcomm.discovery.queryFeatures({ awaitDisclosures: true, connectionId: mediator.id, protocolVersion: 'v1', diff --git a/app/src/utils/bc-agent-modules.ts b/app/src/utils/bc-agent-modules.ts index 6ce9960..1c70bd9 100644 --- a/app/src/utils/bc-agent-modules.ts +++ b/app/src/utils/bc-agent-modules.ts @@ -1,72 +1,61 @@ import { - AnonCredsCredentialFormatService, + AnonCredsDidCommCredentialFormatService, + AnonCredsDidCommProofFormatService, AnonCredsModule, - AnonCredsProofFormatService, - DataIntegrityCredentialFormatService, - LegacyIndyCredentialFormatService, - LegacyIndyProofFormatService, - V1CredentialProtocol, - V1ProofProtocol, + DataIntegrityDidCommCredentialFormatService, + DidCommCredentialV1Protocol, + DidCommProofV1Protocol, + LegacyIndyDidCommCredentialFormatService, + LegacyIndyDidCommProofFormatService, } from '@credo-ts/anoncreds' -import { AskarModule } from '@credo-ts/askar' +import { AskarKeyManagementService, AskarModule } from '@credo-ts/askar' import { Agent, - AutoAcceptCredential, - AutoAcceptProof, - ConnectionsModule, - CredentialsModule, DidsModule, - DifPresentationExchangeProofFormatService, - JsonLdCredentialFormatService, - MediationRecipientModule, - MediatorPickupStrategy, - ProofsModule, - V2CredentialProtocol, - V2ProofProtocol, + JwkDidResolver, + KeyDidResolver, + Kms, + PeerDidResolver, W3cCredentialsModule, + WebDidResolver, } from '@credo-ts/core' -import { DrpcModule } from '@credo-ts/drpc' +import { + DidCommAutoAcceptCredential, + DidCommAutoAcceptProof, + DidCommCredentialV2Protocol, + DidCommDifPresentationExchangeProofFormatService, + DidCommJsonLdCredentialFormatService, + DidCommMediatorPickupStrategy, + DidCommModule, + DidCommProofV2Protocol, +} from '@credo-ts/didcomm' import { IndyVdrAnonCredsRegistry, IndyVdrModule, IndyVdrPoolConfig } from '@credo-ts/indy-vdr' -// DISABLED: Push notifications disabled — no server backend yet -// import { PushNotificationsApnsModule, PushNotificationsFcmModule } from '@credo-ts/push-notifications' -import { WebVhAnonCredsRegistry, WebvhDidResolver } from '@credo-ts/webvh' +import { SecureEnvironmentKeyManagementService } from '@credo-ts/react-native' +import { WebVhAnonCredsRegistry, WebVhDidResolver } from '@credo-ts/webvh' import { anoncreds } from '@hyperledger/anoncreds-react-native' -import { ariesAskar } from '@hyperledger/aries-askar-react-native' import { indyVdr } from '@hyperledger/indy-vdr-react-native' -import { CacheSettings, IndyVdrProxyAnonCredsRegistry, IndyVdrProxyDidResolver } from 'credo-ts-indy-vdr-proxy-client' +import { askar } from '@openwallet-foundation/askar-react-native' import * as BifoldCore from '@bifold/core' export type BCAgent = Agent> interface GetBCAgentModulesOptions { + walletSecret: { id: string; key: string } indyNetworks: IndyVdrPoolConfig[] mediatorInvitationUrl?: string txnCache?: { capacity: number; expiryOffsetMs: number; path?: string } - enableProxy?: boolean - proxyBaseUrl?: string - proxyCacheSettings?: CacheSettings } /** - * Constructs the modules to be used in the agent setup - * @param indyNetworks - * @param mediatorInvitationUrl determine which mediator to use - * @param txnCache optional local cache config for indyvdr - * @param enableProxy boolean from the store to determine if proxy should be used - * @param proxyBaseUrl URL of indy vdr proxy - * @param proxyCacheSettings settings for above mentioned proxy client caching + * Constructs the modules to be used in the agent setup (credo 0.6). + * Mirrors @bifold/core getAgentModules, plus the Keyring additions: + * JSON-LD credential format (VRC), VRC document loader, RelationshipDidModule + * and AttestationStorageModule. * @returns modules to be used in agent setup */ -export function getBCAgentModules({ - indyNetworks, - mediatorInvitationUrl, - txnCache, - enableProxy, - proxyBaseUrl, - proxyCacheSettings, -}: GetBCAgentModulesOptions) { - const indyCredentialFormat = new LegacyIndyCredentialFormatService() - const indyProofFormat = new LegacyIndyProofFormatService() +export function getBCAgentModules({ walletSecret, indyNetworks, mediatorInvitationUrl, txnCache }: GetBCAgentModulesOptions) { + const indyCredentialFormat = new LegacyIndyDidCommCredentialFormatService() + const indyProofFormat = new LegacyIndyDidCommProofFormatService() if (txnCache) { indyVdr.setLedgerTxnCache({ @@ -80,7 +69,16 @@ export function getBCAgentModules({ const modules = { askar: new AskarModule({ - ariesAskar, + enableKms: false, + askar, + store: { id: walletSecret.id, key: walletSecret.key }, + }), + kms: new Kms.KeyManagementModule({ + backends: [ + new AskarKeyManagementService(), + new SecureEnvironmentKeyManagementService({ biometricsBacked: false }), + ], + defaultBackend: 'askar', }), anoncreds: new AnonCredsModule({ anoncreds, @@ -90,66 +88,58 @@ export function getBCAgentModules({ indyVdr, networks: indyNetworks as [IndyVdrPoolConfig], }), - connections: new ConnectionsModule({ - autoAcceptConnections: true, - }), - credentials: new CredentialsModule({ - autoAcceptCredentials: AutoAcceptCredential.ContentApproved, - credentialProtocols: [ - new V1CredentialProtocol({ indyCredentialFormat }), - new V2CredentialProtocol({ - credentialFormats: [ - indyCredentialFormat, - new AnonCredsCredentialFormatService(), - new DataIntegrityCredentialFormatService(), - new JsonLdCredentialFormatService(), - ], - }), - ], - }), - proofs: new ProofsModule({ - autoAcceptProofs: AutoAcceptProof.ContentApproved, - proofProtocols: [ - new V1ProofProtocol({ indyProofFormat }), - new V2ProofProtocol({ - proofFormats: [ - indyProofFormat, - new AnonCredsProofFormatService(), - new DifPresentationExchangeProofFormatService(), - ], - }), - ], - }), - mediationRecipient: new MediationRecipientModule({ - mediatorInvitationUrl: mediatorInvitationUrl, - mediatorPickupStrategy: MediatorPickupStrategy.Implicit, + didcomm: new DidCommModule({ + useDidSovPrefixWhereAllowed: true, + connections: { + autoAcceptConnections: true, + }, + credentials: { + autoAcceptCredentials: DidCommAutoAcceptCredential.ContentApproved, + credentialProtocols: [ + new DidCommCredentialV1Protocol({ indyCredentialFormat }), + new DidCommCredentialV2Protocol({ + credentialFormats: [ + indyCredentialFormat, + new AnonCredsDidCommCredentialFormatService(), + new DataIntegrityDidCommCredentialFormatService(), + new DidCommJsonLdCredentialFormatService(), + ], + }), + ], + }, + proofs: { + autoAcceptProofs: DidCommAutoAcceptProof.ContentApproved, + proofProtocols: [ + new DidCommProofV1Protocol({ indyProofFormat }), + new DidCommProofV2Protocol({ + proofFormats: [ + indyProofFormat, + new AnonCredsDidCommProofFormatService(), + new DidCommDifPresentationExchangeProofFormatService(), + ], + }), + ], + }, + mediationRecipient: { + mediatorInvitationUrl: mediatorInvitationUrl, + mediatorPickupStrategy: DidCommMediatorPickupStrategy.Implicit, + }, }), - // DISABLED: Push notifications disabled — no server backend yet - // pushNotificationsFcm: new PushNotificationsFcmModule(), - // pushNotificationsApns: new PushNotificationsApnsModule(), dids: new DidsModule({ - resolvers: [new WebvhDidResolver()], + resolvers: [ + new WebVhDidResolver(), + new WebDidResolver(), + new JwkDidResolver(), + new KeyDidResolver(), + new PeerDidResolver(), + ], }), w3cCredentials: new W3cCredentialsModule({ documentLoader: (BifoldCore as any).createVrcDocumentLoader, }), - drpc: new DrpcModule(), relationshipDid: new RelationshipDidModule(), attestationStorage: new AttestationStorageModule(), } - if (enableProxy && proxyBaseUrl) { - modules.anoncreds = new AnonCredsModule({ - anoncreds, - registries: [ - new IndyVdrProxyAnonCredsRegistry({ proxyBaseUrl, cacheOptions: proxyCacheSettings }), - new WebVhAnonCredsRegistry(), - ], - }) - modules.dids = new DidsModule({ - resolvers: [new IndyVdrProxyDidResolver({ proxyBaseUrl }), new WebvhDidResolver()], - }) - } - return modules } diff --git a/app/src/utils/credentials.ts b/app/src/utils/credentials.ts index ce6c19c..12127ce 100644 --- a/app/src/utils/credentials.ts +++ b/app/src/utils/credentials.ts @@ -4,7 +4,7 @@ import { AnonCredsRequestedAttributeMatch, AnonCredsRequestedPredicateMatch, } from '@credo-ts/anoncreds' -import { CredentialExchangeRecord, ProofExchangeRecord, GetCredentialsForProofRequestReturn } from '@credo-ts/core' +import { DidCommCredentialExchangeRecord, DidCommProofExchangeRecord, GetCredentialsForProofRequestReturn } from '@credo-ts/didcomm' import { BifoldAgent } from '@bifold/core' import { Attribute, Predicate } from '@bifold/oca/build/legacy' @@ -14,7 +14,7 @@ export type ProofCredentialItems = ProofCredentialAttributes & ProofCredentialPr export type ProofCredentialAttributes = { altCredentials?: string[] - credExchangeRecord?: CredentialExchangeRecord + credExchangeRecord?: DidCommCredentialExchangeRecord credId: string credDefId?: string proofCredDefId?: string @@ -26,7 +26,7 @@ export type ProofCredentialAttributes = { export type ProofCredentialPredicates = { altCredentials?: string[] - credExchangeRecord?: CredentialExchangeRecord + credExchangeRecord?: DidCommCredentialExchangeRecord credId: string credDefId?: string proofCredDefId?: string @@ -124,7 +124,7 @@ export const evaluatePredicates = * @returns The Anoncreds or Indy proof format object */ const formatForProofWithId = async (agent: BifoldAgent, proofId: string, filterByNonRevocationRequirements = false) => { - const format = await agent.proofs.getFormatData(proofId) + const format = await agent.modules.didcomm.proofs.getFormatData(proofId) const proofIsAnoncredsFormat = format.request?.anoncreds !== undefined const proofIsIndycredsFormat = format.request?.indy !== undefined const proofFormats = { @@ -168,12 +168,12 @@ const formatForProofWithId = async (agent: BifoldAgent, proofId: string, filterB */ export const credentialsMatchForProof = async ( agent: BifoldAgent, - proof: ProofExchangeRecord, + proof: DidCommProofExchangeRecord, filterByNonRevocationRequirements = true ): Promise => { const proofFormats = await formatForProofWithId(agent, proof.id, filterByNonRevocationRequirements) - const credentials = await agent.proofs.getCredentialsForRequest({ - proofRecordId: proof.id, + const credentials = await agent.modules.didcomm.proofs.getCredentialsForRequest({ + proofExchangeRecordId: proof.id, proofFormats, }) diff --git a/app/src/utils/drpc.ts b/app/src/utils/drpc.ts deleted file mode 100644 index c647bd1..0000000 --- a/app/src/utils/drpc.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Agent, ConnectionRecord } from '@credo-ts/core' -import { DrpcRequest, DrpcResponseObject } from '@credo-ts/drpc' - -export type DrpcResponsePromise = (responseTimeout: number) => Promise - -export type AttestationRequestParams = { - attestation_object: string - platform: 'apple' | 'google' - os_version: string - app_version: string - key_id?: string // Apple only -} - -export type NonceDrpcResponse = DrpcResponseObject & { - result?: { - nonce: string - } -} - -export type AttestationResult = { - status: 'success' | 'failure' -} - -export type AttestationDrpcResponse = DrpcResponseObject & { - result?: AttestationResult -} - -// These are the methods that the DRPC server supports. They -// should map to a handler on the controller. -const DrpcMethod = { - RequestNonceV2: 'request_nonce_v2', - RequestAttestationV2: 'request_attestation_v2', -} as const - -export const sendDrpcRequest = async ( - agent: Agent, - connectionId: string, - request: Partial - // eslint-disable-next-line @typescript-eslint/no-explicit-any -): Promise> => { - const requestWithId = { jsonrpc: '2.0', id: Math.floor(Math.random() * 900000) + 100000, ...request } - - return await agent.modules.drpc.sendRequest(connectionId, requestWithId) -} - -export const requestNonceDrpc = async ( - agent: Agent, - connectionRecord: ConnectionRecord -): Promise> => { - const request: Partial = { - method: DrpcMethod.RequestNonceV2, - } - - return await sendDrpcRequest(agent, connectionRecord.id, request) -} - -export const requestAttestationDrpc = async ( - agent: Agent, - connectionRecord: ConnectionRecord, - params: AttestationRequestParams -): Promise> => { - const request: Partial = { - method: DrpcMethod.RequestAttestationV2, - params, - } - - return await sendDrpcRequest(agent, connectionRecord.id, request) -} diff --git a/app/src/utils/mediator.ts b/app/src/utils/mediator.ts index eede53b..a07e1ab 100644 --- a/app/src/utils/mediator.ts +++ b/app/src/utils/mediator.ts @@ -1,10 +1,11 @@ -import { Agent, MediatorPickupStrategy } from '@credo-ts/core' +import { Agent } from '@credo-ts/core' +import { DidCommMediatorPickupStrategy } from '@credo-ts/didcomm' export const batchPickup = async (agent: Agent): Promise => { try { for (let i = 0; i < 2; i++) { agent.config.logger.debug(`Batch pickup attempt ${i + 1}`) - agent.mediationRecipient.initiateMessagePickup(undefined, MediatorPickupStrategy.Implicit) + agent.modules.didcomm.mediationRecipient.initiateMessagePickup(undefined, DidCommMediatorPickupStrategy.Implicit) await new Promise((resolve) => setTimeout(resolve, 50)) } } catch (error) { @@ -15,10 +16,10 @@ export const batchPickup = async (agent: Agent): Promise => { export const startPeriodicTrustPing = (agent: Agent, intervalMs: number): (() => void) => { const id = setInterval(async () => { try { - const mediator = await agent.mediationRecipient.findDefaultMediator() + const mediator = await agent.modules.didcomm.mediationRecipient.findDefaultMediator() if (!mediator) return - await agent.connections.sendPing(mediator.connectionId, { + await agent.modules.didcomm.connections.sendPing(mediator.connectionId, { responseRequested: false, withReturnRouting: true, }) diff --git a/app/storybook/addons.ts b/app/storybook/addons.ts deleted file mode 100644 index 429196c..0000000 --- a/app/storybook/addons.ts +++ /dev/null @@ -1,4 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import '@storybook/addon-actions' -import '@storybook/addon-links' -import '@storybook/addon-knobs' diff --git a/app/storybook/index.ts b/app/storybook/index.ts deleted file mode 100644 index 0efc575..0000000 --- a/app/storybook/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -// if you use expo remove this line -import { withKnobs } from '@storybook/addon-knobs' -import { getStorybookUI, configure, addDecorator } from '@storybook/react-native' -import { Platform } from 'react-native' - -import './rn-addons' - -// enables knobs for all stories -addDecorator(withKnobs) - -// import stories -configure(() => { - require('./stories') -}, module) - -// Refer to https://github.com/storybookjs/react-native/tree/master/app/react-native#getstorybookui-options -// To find allowed options for getStorybookUI -const StorybookUIRoot = getStorybookUI({ - host: Platform.OS === 'android' ? '10.0.2.2' : '0.0.0.0', - asyncStorage: null, -}) - -// If you are using React Native vanilla and after installation you don't see your app name here, write it manually. -// If you use Expo you should remove this line. -//AppRegistry.registerComponent('%APP_NAME%', () => StorybookUIRoot) - -export default StorybookUIRoot diff --git a/app/storybook/rn-addons.ts b/app/storybook/rn-addons.ts deleted file mode 100644 index 88595a3..0000000 --- a/app/storybook/rn-addons.ts +++ /dev/null @@ -1,3 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import '@storybook/addon-ondevice-actions/register' -import '@storybook/addon-ondevice-knobs/register' diff --git a/app/storybook/stories/Brandings/Brandings.stories.tsx b/app/storybook/stories/Brandings/Brandings.stories.tsx deleted file mode 100644 index ce3a5c0..0000000 --- a/app/storybook/stories/Brandings/Brandings.stories.tsx +++ /dev/null @@ -1,295 +0,0 @@ -import { - components, - ContainerProvider, - contexts, - MainContainer, - StoreContext, - ThemeProvider, - TOKENS, -} from '@bifold/core' -import { BrandingOverlayType, RemoteOCABundleResolver } from '@bifold/oca/build/legacy' -import { AnonCredsCredentialMetadataKey } from '@credo-ts/anoncreds/build/utils/metadata' -import { - CredentialExchangeRecord, - CredentialExchangeRecordProps, - CredentialPreviewAttribute, - CredentialRole, - CredentialState, - RevocationNotification, -} from '@credo-ts/core' -import { select } from '@storybook/addon-knobs' -import { storiesOf } from '@storybook/react-native' -import React, { Dispatch, PropsWithChildren, useEffect, useMemo, useState } from 'react' -import { useTranslation } from 'react-i18next' -import { FlatList, ListRenderItem, View } from 'react-native' -import { Config } from 'react-native-config' -import { container } from 'tsyringe' - -import { KeyRingThemeNames } from '@/constants' -import { themes } from '@/theme' - -const OCABundleResolver = new RemoteOCABundleResolver(Config.OCA_URL ?? '', { - brandingOverlayType: BrandingOverlayType.Branding10, -}) -const BasicAppContext: React.FC = ({ children }) => { - const context = useMemo(() => new MainContainer(container.createChildContainer()).init(), []) - context.container.registerInstance(TOKENS.UTIL_OCA_RESOLVER, OCABundleResolver) - return {children} -} - -enum CREDENTIALS { - LSBC_TEST = 'AuJrigKQGRLJajKAebTgWu:3:CL:209526:default', - LSBC_PROD = '4xE68b6S5VRFrKMMG1U95M:3:CL:59232:default', - SHOWCASE_LAWYER_DEV = 'L6ASjmDDbDH7yPL1t2yFj9:2:member_card:1.53', - SHOWCASE_LAWYER_TEST = 'M6dhuFj5UwbhWkSLmvYSPc:2:member_card:1.53', - SHOWCASE_LAWYER_PROD = 'QEquAHkM35w4XVT3Ku5yat:2:member_card:1.53', - SHOWCASE_STUDENT_DEV = 'L6ASjmDDbDH7yPL1t2yFj9:2:student_card:1.2', - SHOWCASE_STUDENT_TEST = 'M6dhuFj5UwbhWkSLmvYSPc:2:student_card:1.2', - SHOWCASE_STUDENT_PROD = 'QEquAHkM35w4XVT3Ku5yat:2:student_card:1.2', - SHOWCASE_LAWYER2_PERSON_DEV = 'L6ASjmDDbDH7yPL1t2yFj9:2:Person:1.2', - SHOWCASE_LAWYER2_PERSON_TEST = 'M6dhuFj5UwbhWkSLmvYSPc:2:Person:1.2', - SHOWCASE_LAWYER2_PERSON_PROD = 'QEquAHkM35w4XVT3Ku5yat:2:Person:1.2', - UNVERIFIED_PERSON_DEV = 'Ui6HA36FvN83cEtmYYHxrn:2:unverified_person:0.1.0', - UNVERIFIED_PERSON_TEST = 'HTkhhCW1bAXWnxC1u3YVoa:2:unverified_person:0.1.0', - UNVERIFIED_PERSON_PROD = 'YXCtXE4YhVjULgj5hrk4ML:2:unverified_person:0.1.0', - PILOT_INVITE_DEV = 'Mp2pDQqS2eSjNVA7kXc8ut:2:BC VC Pilot Certificate:1.0.1', - PILOT_INVITE_TEST = '4zBepKVWZcGTzug4X49vAN:2:BC VC Pilot Certificate:1.0.1', - PILOT_INVITE_PROD = 'E2h4RUJxyh48PLJ1CtGJrq:2:BC VC Pilot Certificate:1.0.1', - BC_DIGITAL_ID_QA = 'KCxVC8GkKywjhWJnUfCmkW:3:CL:20:PersonQA', - BC_DIGITAL_ID_SIT = '7xjfawcnyTUcduWVysLww5:3:CL:28075:PersonSIT', - BC_DIGITAL_ID_DEV = 'XpgeQa93eZvGSZBZef3PHn:3:CL:28075:PersonDEV', - BC_DIGITAL_ID_PROD = 'RGjWbW1eycP7FrMf4QJvX8:3:CL:13:Person', -} - -enum CREDENTIAL_DEFINITION { - Generic = 'asdasdasd:2:generic:1.0:Generic', -} - -const { - misc: { CredentialCard }, -} = components - -type CredentialProps = { - credentialRecordId: string - revoked?: boolean - credentialDefinitionId: string - connectionId?: string -} - -const CredentialWrapper = ({ - revoked = false, - credentialRecordId, - credentialDefinitionId, - connectionId, -}: CredentialProps) => { - const indyCredential = { credentialRecordType: 'indy', credentialRecordId } - const props: CredentialExchangeRecordProps = { - role: CredentialRole.Issuer, - connectionId: connectionId, - threadId: '', - state: CredentialState.CredentialIssued, - protocolVersion: '1.0', - credentials: [indyCredential], - } - const credDefIdParts = credentialDefinitionId.split(':') - if (credDefIdParts[2] === 'CL' && credDefIdParts[4] === 'Person') { - props.credentialAttributes = [ - new CredentialPreviewAttribute({ name: 'given_names', value: 'John' }), - new CredentialPreviewAttribute({ name: 'family_name', value: 'Doe' }), - ] - } - const credential: CredentialExchangeRecord = new CredentialExchangeRecord(props) - credential.metadata.set(AnonCredsCredentialMetadataKey, { - credentialDefinitionId: credentialDefinitionId, - schemaId: '', - }) - if (revoked) { - credential.revocationNotification = new RevocationNotification() - } - return -} - -type ListItem = { - credentialDefinitionId: string - credentialRecordId: string - revoked: boolean - connectionId?: string -} - -type CredentialsProps = { items: ListItem[] } - -const ItemDivider = () => { - return ( - - ) -} - -const Credentials = ({ items }: CredentialsProps) => { - const lang = select('Language', ['en', 'fr', 'pt'], 'en') - const { i18n } = useTranslation() - const [isLoaded, setLoaded] = useState(false) - const renderItem: ListRenderItem = ({ item, index }): JSX.Element => { - return ( - - ) - } - useEffect(() => { - async function changeFlag() { - await i18n.changeLanguage(lang) - setLoaded(true) - } - changeFlag() - }, [lang, i18n]) - return ( - <> - {isLoaded && ( - - )} - - ) -} - -storiesOf('Brandings', module) - .add('All', () => { - const state = contexts.store.defaultState - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const dispatch: Dispatch = () => { - return - } - const list: ListItem[] = [ - { - credentialDefinitionId: CREDENTIALS.BC_DIGITAL_ID_PROD, - credentialRecordId: 'PersonCredential_default', - revoked: false, - }, - { - credentialDefinitionId: CREDENTIALS.BC_DIGITAL_ID_PROD, - credentialRecordId: 'PersonCredential_Revoked', - revoked: true, - }, - { - credentialDefinitionId: CREDENTIALS.SHOWCASE_STUDENT_PROD, - credentialRecordId: 'StudentCredential_default', - revoked: false, - }, - { - credentialDefinitionId: CREDENTIALS.SHOWCASE_STUDENT_PROD, - credentialRecordId: 'StudentCredential_Revoked', - revoked: true, - }, - { credentialDefinitionId: CREDENTIALS.LSBC_PROD, credentialRecordId: 'Lawyer_default', revoked: false }, - { credentialDefinitionId: CREDENTIALS.LSBC_PROD, credentialRecordId: 'Lawyer_Revoked', revoked: true }, - { - credentialDefinitionId: CREDENTIALS.PILOT_INVITE_PROD, - credentialRecordId: 'Pilot_default', - revoked: false, - }, - { - credentialDefinitionId: CREDENTIALS.PILOT_INVITE_PROD, - credentialRecordId: 'Pilot_Revoked', - revoked: true, - }, - { - credentialDefinitionId: CREDENTIALS.UNVERIFIED_PERSON_PROD, - credentialRecordId: 'unverified_person_default', - revoked: false, - }, - { - credentialDefinitionId: CREDENTIALS.UNVERIFIED_PERSON_PROD, - credentialRecordId: 'unverified_person_Revoked', - revoked: true, - }, - { credentialDefinitionId: CREDENTIAL_DEFINITION.Generic, credentialRecordId: 'Generic_default', revoked: false }, - { - credentialDefinitionId: CREDENTIAL_DEFINITION.Generic, - credentialRecordId: 'Generic_Revoked', - revoked: true, - connectionId: 'ACME', - }, - { - credentialDefinitionId: CREDENTIAL_DEFINITION.Generic, - credentialRecordId: 'Generic_Revoked', - revoked: true, - connectionId: 'ab2c9305-282e-42da-82d9-70d3e99ecb02', - }, - { - credentialDefinitionId: CREDENTIAL_DEFINITION.Generic, - credentialRecordId: 'Generic_Revoked', - revoked: true, - connectionId: 'ab2c9305-282e-42da-82d9-70d3e99ecb02-70d3e99ecb02', - }, - { - credentialDefinitionId: CREDENTIAL_DEFINITION.Generic, - credentialRecordId: 'Generic_Revoked', - revoked: true, - connectionId: 'ab2c9305-282e-42da-82d9-70d3e99ecb02-70d3e99ecb02-282e-42da-82d9-70d3e99ecb02-70d3e99ecb02', - }, - ] - return ( - - - - - - - - ) - }) - .add('Person: Default', (): React.ReactNode => { - const state = contexts.store.defaultState - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const dispatch: Dispatch = () => { - return - } - const list: ListItem[] = [ - { - credentialDefinitionId: CREDENTIALS.BC_DIGITAL_ID_PROD, - credentialRecordId: 'PersonCredential_default', - revoked: false, - }, - ] - return ( - <> - - - - - - - - - ) - }) - .add('Person: Revoked', (): React.ReactNode => { - const state = contexts.store.defaultState - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const dispatch: Dispatch = () => { - return - } - const list: ListItem[] = [ - { - credentialDefinitionId: CREDENTIALS.BC_DIGITAL_ID_PROD, - credentialRecordId: 'PersonCredential_Revoked', - revoked: true, - }, - ] - return ( - - - - - - ) - }) diff --git a/app/storybook/stories/Button/Button.stories.tsx b/app/storybook/stories/Button/Button.stories.tsx deleted file mode 100644 index 6049ec9..0000000 --- a/app/storybook/stories/Button/Button.stories.tsx +++ /dev/null @@ -1,46 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ -import { components, ThemeProvider } from '@bifold/core' -import { storiesOf } from '@storybook/react-native' -import React from 'react' -import { ScrollView, Text, View } from 'react-native' -import { SafeAreaView } from 'react-native-safe-area-context' - -import { KeyRingThemeNames } from '@/constants' -import { themes } from '@/theme' - -const Button = components.buttons.Button.default -const ButtonType = components.buttons.Button.ButtonType - -storiesOf('Button', module) - //.addDecorator((getStory) => {getStory()}) - .add('All', () => { - const items = [] - for (const buttonType of [ButtonType.Primary, ButtonType.Secondary, ButtonType.Critical]) { - let title = 'Primary' - switch (buttonType) { - case ButtonType.Secondary: - title = 'Secondary' - break - case ButtonType.Critical: - title = 'Critical' - break - } - for (const enabled of [true, false]) { - items.push( - - {title} (enabled={`${enabled}`}) - - ) - items.push(