├── .nvmrc ├── app ├── .ruby-version ├── ios │ ├── .ruby-version │ ├── Media.xcassets │ │ ├── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── iTunesArtwork.png │ │ │ ├── iTunesArtwork_Dark.png │ │ │ ├── iTunesArtwork_Tinted.png │ │ │ └── Contents.json │ ├── AriesBifold-Bridging-Header.h │ ├── AriesBifold │ │ ├── AppDelegate.h │ │ ├── AriesBifold.entitlements │ │ └── main.m │ ├── AriesBifold.swift │ ├── AriesBifold.xcworkspace │ │ ├── xcshareddata │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ └── IDEWorkspaceChecks.plist │ │ └── contents.xcworkspacedata │ ├── .xcode.env │ ├── AriesBifoldTests │ │ └── Info.plist │ └── GoogleService-Info.plist ├── .npmrc ├── __mocks__ │ ├── file.js │ ├── style.js │ ├── @credo-ts │ │ └── react-native.ts │ ├── react-native-fs.ts │ ├── @hyperledger │ │ ├── indy-vdr-react-native.ts │ │ ├── anoncreds-react-native.ts │ │ └── aries-askar-react-native.ts │ ├── custom │ │ ├── @react-navigation │ │ │ ├── native.ts │ │ │ └── core.ts │ │ ├── react-native-camera.ts │ │ └── react-native-localize.ts │ ├── react-native-argon2.js │ ├── @react-native-firebase │ │ └── messaging.ts │ ├── react-native-keychain.ts │ ├── react-native-bcsc-core.ts │ ├── @react-native-async-storage │ │ └── async-storage.js │ ├── react-native-volume-manager.ts │ ├── react-native-permissions.ts │ ├── @pexip │ │ └── infinity-api.ts │ ├── @react-native-clipboard │ │ └── clipboard.js │ ├── react-native-screenguard.ts │ ├── react-native-incall-manager.ts │ ├── react-i18next.ts │ ├── react-native-tcp-socket │ │ └── index.ts │ ├── @react-navigation │ │ ├── core.ts │ │ └── native.ts │ └── @react-native-community │ │ └── netinfo.ts ├── reactNativePermissionsIOS.json ├── app.json ├── .bundle │ └── config ├── react-native.config.js ├── android │ ├── app │ │ ├── debug.keystore │ │ ├── release.keystore │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── values │ │ │ │ │ │ ├── strings.xml │ │ │ │ │ │ ├── colors.xml │ │ │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ │ │ └── styles.xml │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ ├── drawable │ │ │ │ │ │ ├── ic_launcher_mono.png │ │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ │ └── ic_launcher_play_store.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ │ ├── drawable-hdpi │ │ │ │ │ │ └── ic_notification.png │ │ │ │ │ ├── drawable-mdpi │ │ │ │ │ │ └── ic_notification.png │ │ │ │ │ ├── drawable-xhdpi │ │ │ │ │ │ └── ic_notification.png │ │ │ │ │ ├── drawable-xxhdpi │ │ │ │ │ │ └── ic_notification.png │ │ │ │ │ ├── drawable-xxxhdpi │ │ │ │ │ │ └── ic_notification.png │ │ │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ │ │ ├── ic_launcher.xml │ │ │ │ │ │ └── ic_launcher_round.xml │ │ │ │ │ └── layout │ │ │ │ │ │ └── launch_screen.xml │ │ │ │ ├── ic_launcher-playstore.png │ │ │ │ └── assets │ │ │ │ │ └── fonts │ │ │ │ │ ├── BCSans-Bold.ttf │ │ │ │ │ ├── BCSans-Italic.ttf │ │ │ │ │ ├── BCSans-Regular.ttf │ │ │ │ │ └── BCSans-BoldItalic.ttf │ │ │ └── debug │ │ │ │ └── AndroidManifest.xml │ │ ├── proguard-rules.pro │ │ ├── build_defs.bzl │ │ ├── .idea │ │ │ └── modules │ │ │ │ └── app.iml │ │ └── google-services.json │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── settings-gradle.lockfile │ └── settings.gradle ├── src │ ├── assets │ │ ├── img │ │ │ ├── analytics.png │ │ │ ├── combo_card.png │ │ │ ├── logo-large.png │ │ │ ├── photo_card.png │ │ │ ├── qr-code-scan.png │ │ │ ├── FirstTutorial.jpg │ │ │ ├── SecondTutorial.jpg │ │ │ ├── ThirdTutorial.jpg │ │ │ ├── logo-large@2x.png │ │ │ ├── logo-large@3x.png │ │ │ ├── no_photo_card.png │ │ │ ├── notifications.png │ │ │ ├── qr-code-phone.png │ │ │ ├── selfie_example.png │ │ │ ├── credential-scan.png │ │ │ ├── logo-large-white.png │ │ │ ├── list-of-credentials.jpg │ │ │ ├── push-notifications.png │ │ │ ├── tab-navigator-account.png │ │ │ ├── card_not_found_highlight.png │ │ │ ├── highlight_serial_barcode.png │ │ │ ├── notifications-screencap.png │ │ │ ├── proof-request-illustration.png │ │ │ ├── transfer-account-two-phones.png │ │ │ ├── credential-offer-illustration.png │ │ │ ├── mobile-phone-scanning-laptop.jpg │ │ │ └── credentialIcon.svg │ │ └── fonts │ │ │ ├── BCSans-Bold.ttf │ │ │ ├── BCSans-Italic.ttf │ │ │ ├── BCSans-Regular.ttf │ │ │ ├── MaterialIcons.ttf │ │ │ └── BCSans-BoldItalic.ttf │ ├── events │ │ ├── eventTypes.ts │ │ └── alertEvents.ts │ ├── utils │ │ ├── splitSplice.ts │ │ ├── expiration.ts │ │ ├── mediator.ts │ │ ├── analytics │ │ │ └── analytics-singleton.ts │ │ ├── links.ts │ │ └── net-info-config.ts │ ├── theme.ts │ ├── configs │ │ └── ledgers │ │ │ └── indy │ │ │ └── ledgers.ts │ ├── bcsc-theme │ │ ├── features │ │ │ ├── deep-linking │ │ │ │ ├── index.ts │ │ │ │ ├── useHasPendingDeepLink.ts │ │ │ │ └── DeepLinkViewModelContext.tsx │ │ │ ├── verify │ │ │ │ └── live-call │ │ │ │ │ ├── utils │ │ │ │ │ ├── formatCallTime.ts │ │ │ │ │ └── clearTimeoutIfExists.ts │ │ │ │ │ └── components │ │ │ │ │ └── CallProcessingView.tsx │ │ │ ├── webview │ │ │ │ ├── MainWebViewScreen.tsx │ │ │ │ ├── VerifyWebViewScreen.tsx │ │ │ │ └── OnboardingWebViewScreen.tsx │ │ │ ├── settings │ │ │ │ ├── MainContactUsScreen.tsx │ │ │ │ └── VerifyContactUsScreen.tsx │ │ │ ├── account │ │ │ │ ├── components │ │ │ │ │ ├── AccountField.tsx │ │ │ │ │ └── AccountPhoto.tsx │ │ │ │ └── NicknameAccountScreen.tsx │ │ │ ├── onboarding │ │ │ │ └── OnboardingOptInAnalyticsScreen.tsx │ │ │ ├── services │ │ │ │ └── components │ │ │ │ │ └── ServiceButton.tsx │ │ │ └── home │ │ │ │ └── components │ │ │ │ └── HomeHeader.tsx │ │ ├── api │ │ │ ├── workflow │ │ │ │ └── key-rotation.workflow.ts │ │ │ └── hooks │ │ │ │ ├── withAccountGuard.ts │ │ │ │ └── useJwksApi.tsx │ │ ├── types │ │ │ └── cards.ts │ │ ├── navigators │ │ │ └── stack-utils.ts │ │ ├── utils │ │ │ ├── account-utils.ts │ │ │ └── card-utils.ts │ │ ├── components │ │ │ ├── TabScreenWrapper.tsx │ │ │ ├── HeaderBackButton.tsx │ │ │ └── GenericCardImage.tsx │ │ └── hooks │ │ │ └── useBCSCApiClient.tsx │ ├── localization │ │ └── index.ts │ ├── bcwallet-theme │ │ ├── features │ │ │ └── tours │ │ │ │ ├── hooks │ │ │ │ └── tour-image-dimensions.ts │ │ │ │ └── index.ts │ │ └── components │ │ │ └── AddCredentialButton.tsx │ ├── Root.tsx │ ├── hooks │ │ ├── useDebounce.tsx │ │ └── useEventListener.tsx │ ├── screens │ │ └── WebDisplay.tsx │ ├── components │ │ └── LoadingIcon.tsx │ └── services │ │ └── version.ts ├── .prettierrc ├── __tests__ │ ├── components │ │ ├── __snapshots__ │ │ │ ├── HomeHeaderView.test.tsx.snap │ │ │ └── LoadingIcon.test.tsx.snap │ │ ├── EmptyList.test.tsx │ │ ├── HomeHeaderView.test.tsx │ │ ├── AddCredentialButton.test.tsx │ │ ├── ErrorTextBox.test.tsx │ │ ├── LoadingIcon.test.tsx │ │ ├── ProgressBar.test.tsx │ │ └── NavigationContainerContext.test.tsx │ ├── screens │ │ ├── __snapshots__ │ │ │ ├── TransferQRDisplayScreen.test.tsx.snap │ │ │ ├── ServiceLoginScreen.test.tsx.snap │ │ │ ├── VerificationMethodSelectionScreen.test.tsx.snap │ │ │ ├── EvidenceCaptureScreen.test.tsx.snap │ │ │ ├── MainWebViewScreen.test.tsx.snap │ │ │ ├── VerifyWebViewScreen.test.tsx.snap │ │ │ └── OnboardingWebViewScreen.test.tsx.snap │ │ ├── EditNicknameScreen.test.tsx │ │ ├── NicknameAccountScreen.test.tsx │ │ ├── MismatchedSerialScreen.test.tsx │ │ ├── TransferQRDisplayScreen.test.tsx │ │ ├── VerificationSuccessScreen.test.tsx │ │ ├── TransferInformationScreen.test.tsx │ │ ├── TransferInstructionsScreen.test.tsx │ │ ├── AccountSetupSelectionScreen.test.tsx │ │ ├── RemoveAccountConfirmationScreen.test.tsx │ │ ├── AccountRenewalFinalWarningScreen.test.tsx │ │ ├── MainWebViewScreen.test.tsx │ │ ├── RemoteLogWarning.test.tsx │ │ ├── VerifyWebViewScreen.test.tsx │ │ ├── ResidentialAddressScreen.test.tsx │ │ ├── ScanSerialScreen.test.tsx │ │ ├── SetupStepsScreen.test.tsx │ │ ├── SecureAppScreen.test.tsx │ │ ├── StartCallScreen.test.tsx │ │ ├── ManualSerialScreen.test.tsx │ │ ├── TermsOfUseScreen.test.tsx │ │ ├── AccountExpiredScreen.test.tsx │ │ ├── MainSettingsScreen.test.tsx │ │ ├── MainContactUsScreen.test.tsx │ │ ├── LiveCallScreen.test.tsx │ │ ├── PendingReviewScreen.test.tsx │ │ ├── VerifyInPersonScreen.test.tsx │ │ ├── VerifySettingsScreen.test.tsx │ │ ├── IdentitySelectionScreen.test.tsx │ │ ├── VerifyContactUsScreen.test.tsx │ │ ├── EvidenceTypeListScreen.test.tsx │ │ ├── OnboardingWebViewScreen.test.tsx │ │ ├── SerialInstructionsScreen.test.tsx │ │ ├── ForgetAllPairingsScreen.test.tsx │ │ ├── SuccessfullySentScreen.test.tsx │ │ ├── VideoInstructionsScreen.test.tsx │ │ ├── BeforeYouCallScreen.test.tsx │ │ ├── SettingsPrivacyPolicyScreen.test.tsx │ │ ├── VideoTooLongScreen.test.tsx │ │ ├── CallBusyOrClosedScreen.test.tsx │ │ ├── OnboardingPrivacyPolicyScreen.test.tsx │ │ ├── AccountRenewalInformationScreen.test.tsx │ │ ├── AccountRenewalFirstWarningScreen.test.tsx │ │ ├── VerificationMethodSelectionScreen.test.tsx │ │ ├── DualIdentificationRequiredScreen.test.tsx │ │ ├── PhotoReviewScreen.test.tsx │ │ ├── EnterBirthdateScreen.test.tsx │ │ ├── AdditionalIdentificationRequiredScreen.test.tsx │ │ ├── Developer.test.tsx │ │ ├── NotificationsScreen.test.tsx │ │ ├── EmailConfirmationScreen.test.tsx │ │ ├── IDPhotoInformationScreen.test.tsx │ │ ├── VideoReviewScreen.test.tsx │ │ ├── OnboardingOptInAnalyticsScreen.test.tsx │ │ ├── PhotoInstructionsScreen.test.tsx │ │ ├── InformationRequiredScreen.test.tsx │ │ └── PersonCredential.test.tsx │ ├── contexts │ │ └── auth.ts │ ├── helpers │ │ └── Utils.test.ts │ └── bcsc-theme │ │ └── components │ │ ├── __snapshots__ │ │ └── PairingCodeTextInput.test.tsx.snap │ │ └── LoadingScreenContent.test.tsx ├── .prettierignore ├── Gemfile ├── declarations.d.ts ├── babel.config.js └── tsconfig.json ├── packages └── bcsc-core │ ├── .watchmanconfig │ ├── .yarnrc.yml │ ├── src │ └── __tests__ │ │ └── index.test.tsx │ ├── tsconfig.build.json │ ├── babel.config.js │ ├── android │ ├── src │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── bcsccore │ │ │ │ │ ├── bcsc-file-port │ │ │ │ │ ├── consumer-rules.pro │ │ │ │ │ ├── src │ │ │ │ │ │ └── main │ │ │ │ │ │ │ └── java │ │ │ │ │ │ │ └── com │ │ │ │ │ │ │ └── bcsccore │ │ │ │ │ │ │ └── fileport │ │ │ │ │ │ │ ├── encryption │ │ │ │ │ │ │ ├── KeySource.java │ │ │ │ │ │ │ └── Encryption.java │ │ │ │ │ │ │ └── decryption │ │ │ │ │ │ │ ├── DecryptionException.java │ │ │ │ │ │ │ └── FileDecryptor.java │ │ │ │ │ ├── proguard-rules.pro │ │ │ │ │ └── build.gradle │ │ │ │ │ └── bcsc-keypair-port │ │ │ │ │ ├── core │ │ │ │ │ └── exceptions │ │ │ │ │ │ ├── KeypairGenerationException.java │ │ │ │ │ │ └── AlertKey.java │ │ │ │ │ └── build.gradle.template │ │ │ ├── AndroidManifestNew.xml │ │ │ └── AndroidManifest.xml │ │ └── newarch │ │ │ └── BcscCoreSpec.kt │ └── gradle.properties │ ├── ios │ ├── BcscCore-Bridging-Header.h │ └── JOSEException.swift │ ├── react-native.config.js │ ├── README.md │ ├── tsconfig.json │ ├── turbo.json │ ├── BcscCore.podspec │ └── eslint.config.mjs ├── .editorconfig ├── .tool-versions ├── .yarnrc.yml ├── .github ├── ISSUE_TEMPLATE │ ├── 4-general.md │ ├── 2-feature-request.md │ ├── 1-bug-report.md │ └── 3-help.md ├── pull_request_template.md └── workflows │ ├── scanner.yml │ └── actions │ ├── setup-node │ └── action.yml │ ├── export-ios-archive │ └── action.yml │ └── send-rocketchat-notification │ └── action.yml ├── .vscode ├── extensions.json └── settings.json ├── docs ├── hot-reload-link-2.png ├── intellij-debug-btn.png ├── intellij-debugging.png ├── BCWallet_Architecture.png ├── Emulator-debug-menu.png ├── extended-controls-kebob.png ├── intellij-run-debug-config.png └── android-studio-java-setting.png ├── release.xcconfig ├── scripts ├── gpublish │ ├── README.md │ └── package.json ├── makeauthkey.sh ├── bump_ios_build.sh └── makepp.sh ├── update-lock-files ├── COMPLIANCE.yaml ├── commitlint.config.js ├── .yarn └── patches │ ├── @credo-ts-indy-vdr-npm-0.5.17-aa0b05041f.patch │ ├── @hyperledger-indy-vdr-shared-npm-0.2.2-b989282fc6.patch │ ├── @animo-id-pex-npm-4.1.1-alpha.0-f29edfffa2.patch │ └── @sphereon-pex-npm-5.0.0-unstable.24-921df3a8ac.patch ├── export-options-bcw.plist ├── export-options-sa.plist ├── .sonarcloud.properties ├── devops └── charts │ └── loki-logstack │ ├── templates │ └── routes.yaml │ └── Chart.yaml ├── CONTRIBUTING.md ├── options-dev.plist ├── PATCH_NOTES.md ├── ios-certificate.md └── .gitignore /.nvmrc: -------------------------------------------------------------------------------- 1 | 20.19.2 -------------------------------------------------------------------------------- /app/.ruby-version: -------------------------------------------------------------------------------- 1 | 2.7.8 2 | -------------------------------------------------------------------------------- /app/ios/.ruby-version: -------------------------------------------------------------------------------- 1 | 2.7.8 2 | -------------------------------------------------------------------------------- /app/.npmrc: -------------------------------------------------------------------------------- 1 | legacy-peer-deps=true 2 | -------------------------------------------------------------------------------- /packages/bcsc-core/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | end_of_line = lf 3 | -------------------------------------------------------------------------------- /app/__mocks__/file.js: -------------------------------------------------------------------------------- 1 | export default '' 2 | -------------------------------------------------------------------------------- /app/__mocks__/style.js: -------------------------------------------------------------------------------- 1 | export default '' 2 | -------------------------------------------------------------------------------- /app/__mocks__/@credo-ts/react-native.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /packages/bcsc-core/.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nmHoistingLimits: workspaces 2 | -------------------------------------------------------------------------------- /app/reactNativePermissionsIOS.json: -------------------------------------------------------------------------------- 1 | ["Camera", "Notifications"] 2 | -------------------------------------------------------------------------------- /app/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "BCWallet", 3 | "displayName": "BC Wallet" 4 | } -------------------------------------------------------------------------------- /packages/bcsc-core/src/__tests__/index.test.tsx: -------------------------------------------------------------------------------- 1 | it.todo('write a test'); 2 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | nodejs 20.19.2 2 | python 3.11.2 3 | java zulu-17.56.15 4 | yarn 4.9.2 -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | compressionLevel: 0 2 | enableGlobalCache: false 3 | nodeLinker: node-modules -------------------------------------------------------------------------------- /app/.bundle/config: -------------------------------------------------------------------------------- 1 | --- 2 | BUNDLE_FORCE_RUBY_PLATFORM: "1" 3 | BUNDLE_FROZEN: "true" 4 | -------------------------------------------------------------------------------- /app/react-native.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | assets: ['./src/assets/fonts'], 3 | } 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/4-general.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "General issue" 3 | about: For everything else 4 | --- 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"] 3 | } 4 | -------------------------------------------------------------------------------- /docs/hot-reload-link-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/docs/hot-reload-link-2.png -------------------------------------------------------------------------------- /docs/intellij-debug-btn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/docs/intellij-debug-btn.png -------------------------------------------------------------------------------- /docs/intellij-debugging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/docs/intellij-debugging.png -------------------------------------------------------------------------------- /app/android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/debug.keystore -------------------------------------------------------------------------------- /docs/BCWallet_Architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/docs/BCWallet_Architecture.png -------------------------------------------------------------------------------- /docs/Emulator-debug-menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/docs/Emulator-debug-menu.png -------------------------------------------------------------------------------- /packages/bcsc-core/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "exclude": ["example", "lib"] 4 | } 5 | -------------------------------------------------------------------------------- /app/android/app/release.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/release.keystore -------------------------------------------------------------------------------- /app/ios/Media.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /app/src/assets/img/analytics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/analytics.png -------------------------------------------------------------------------------- /docs/extended-controls-kebob.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/docs/extended-controls-kebob.png -------------------------------------------------------------------------------- /app/src/assets/img/combo_card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/combo_card.png -------------------------------------------------------------------------------- /app/src/assets/img/logo-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/logo-large.png -------------------------------------------------------------------------------- /app/src/assets/img/photo_card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/photo_card.png -------------------------------------------------------------------------------- /app/src/assets/img/qr-code-scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/qr-code-scan.png -------------------------------------------------------------------------------- /app/src/events/eventTypes.ts: -------------------------------------------------------------------------------- 1 | export enum BCWalletEventTypes { 2 | ADD_CREDENTIAL_PRESSED = 'AddCredentialPressed', 3 | } 4 | -------------------------------------------------------------------------------- /docs/intellij-run-debug-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/docs/intellij-run-debug-config.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | BC Wallet 3 | 4 | -------------------------------------------------------------------------------- /app/src/assets/fonts/BCSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/fonts/BCSans-Bold.ttf -------------------------------------------------------------------------------- /app/src/assets/img/FirstTutorial.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/FirstTutorial.jpg -------------------------------------------------------------------------------- /app/src/assets/img/SecondTutorial.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/SecondTutorial.jpg -------------------------------------------------------------------------------- /app/src/assets/img/ThirdTutorial.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/ThirdTutorial.jpg -------------------------------------------------------------------------------- /app/src/assets/img/logo-large@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/logo-large@2x.png -------------------------------------------------------------------------------- /app/src/assets/img/logo-large@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/logo-large@3x.png -------------------------------------------------------------------------------- /app/src/assets/img/no_photo_card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/no_photo_card.png -------------------------------------------------------------------------------- /app/src/assets/img/notifications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/notifications.png -------------------------------------------------------------------------------- /app/src/assets/img/qr-code-phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/qr-code-phone.png -------------------------------------------------------------------------------- /app/src/assets/img/selfie_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/selfie_example.png -------------------------------------------------------------------------------- /docs/android-studio-java-setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/docs/android-studio-java-setting.png -------------------------------------------------------------------------------- /packages/bcsc-core/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['module:react-native-builder-bob/babel-preset'], 3 | }; 4 | -------------------------------------------------------------------------------- /app/__mocks__/react-native-fs.ts: -------------------------------------------------------------------------------- 1 | const ReactNativeFS = { 2 | RNFSFileTypeRegular: {}, 3 | } 4 | 5 | export default ReactNativeFS 6 | -------------------------------------------------------------------------------- /app/src/assets/fonts/BCSans-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/fonts/BCSans-Italic.ttf -------------------------------------------------------------------------------- /app/src/assets/fonts/BCSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/fonts/BCSans-Regular.ttf -------------------------------------------------------------------------------- /app/src/assets/fonts/MaterialIcons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/fonts/MaterialIcons.ttf -------------------------------------------------------------------------------- /app/src/assets/img/credential-scan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/credential-scan.png -------------------------------------------------------------------------------- /app/src/assets/img/logo-large-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/logo-large-white.png -------------------------------------------------------------------------------- /release.xcconfig: -------------------------------------------------------------------------------- 1 | DEVELOPMENT_TEAM=L796QSLV3E 2 | CODE_SIGN_STYLE = Automatic 3 | CODE_SIGN_IDENTITY = 4 | PROVISIONING_PROFILE_SPECIFIER = -------------------------------------------------------------------------------- /app/src/assets/fonts/BCSans-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/fonts/BCSans-BoldItalic.ttf -------------------------------------------------------------------------------- /app/src/assets/img/list-of-credentials.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/list-of-credentials.jpg -------------------------------------------------------------------------------- /app/src/assets/img/push-notifications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/push-notifications.png -------------------------------------------------------------------------------- /packages/bcsc-core/android/src/main/java/com/bcsccore/bcsc-file-port/consumer-rules.pro: -------------------------------------------------------------------------------- 1 | # No consumer ProGuard rules needed for file port 2 | -------------------------------------------------------------------------------- /app/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /app/src/assets/img/tab-navigator-account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/tab-navigator-account.png -------------------------------------------------------------------------------- /packages/bcsc-core/android/src/main/AndroidManifestNew.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /app/src/assets/img/card_not_found_highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/card_not_found_highlight.png -------------------------------------------------------------------------------- /app/src/assets/img/highlight_serial_barcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/highlight_serial_barcode.png -------------------------------------------------------------------------------- /app/src/assets/img/notifications-screencap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/notifications-screencap.png -------------------------------------------------------------------------------- /app/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "semi": false, 4 | "singleQuote": true, 5 | "plugins": ["prettier-plugin-organize-imports"] 6 | } 7 | -------------------------------------------------------------------------------- /app/android/app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/ios/AriesBifold-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | -------------------------------------------------------------------------------- /app/ios/AriesBifold/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : RCTAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /app/src/assets/img/proof-request-illustration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/proof-request-illustration.png -------------------------------------------------------------------------------- /app/src/assets/img/transfer-account-two-phones.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/transfer-account-two-phones.png -------------------------------------------------------------------------------- /app/__mocks__/@hyperledger/indy-vdr-react-native.ts: -------------------------------------------------------------------------------- 1 | const IndyVDRReactNative = { 2 | install: jest.fn(), 3 | } 4 | 5 | export default IndyVDRReactNative 6 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #003468 4 | -------------------------------------------------------------------------------- /app/src/assets/img/credential-offer-illustration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/credential-offer-illustration.png -------------------------------------------------------------------------------- /app/src/assets/img/mobile-phone-scanning-laptop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/src/assets/img/mobile-phone-scanning-laptop.jpg -------------------------------------------------------------------------------- /app/__mocks__/@hyperledger/anoncreds-react-native.ts: -------------------------------------------------------------------------------- 1 | const AnonCredsReactNative = { 2 | install: jest.fn(), 3 | } 4 | 5 | export default AnonCredsReactNative 6 | -------------------------------------------------------------------------------- /app/__mocks__/@hyperledger/aries-askar-react-native.ts: -------------------------------------------------------------------------------- 1 | const AriesAskarReactNative = { 2 | install: jest.fn(), 3 | } 4 | 5 | export default AriesAskarReactNative 6 | -------------------------------------------------------------------------------- /app/android/app/src/main/assets/fonts/BCSans-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/assets/fonts/BCSans-Bold.ttf -------------------------------------------------------------------------------- /app/android/app/src/main/assets/fonts/BCSans-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/assets/fonts/BCSans-Italic.ttf -------------------------------------------------------------------------------- /app/__mocks__/custom/@react-navigation/native.ts: -------------------------------------------------------------------------------- 1 | const useFocusEffect = jest.fn() 2 | const useIsFocused = jest.fn() 3 | 4 | export { useFocusEffect, useIsFocused } 5 | -------------------------------------------------------------------------------- /app/android/app/src/main/assets/fonts/BCSans-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/assets/fonts/BCSans-Regular.ttf -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/android/app/src/main/assets/fonts/BCSans-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/assets/fonts/BCSans-BoldItalic.ttf -------------------------------------------------------------------------------- /app/android/app/src/main/res/drawable/ic_launcher_mono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/drawable/ic_launcher_mono.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/drawable/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/drawable/ic_launcher_round.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/ios/Media.xcassets/AppIcon.appiconset/iTunesArtwork.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/ios/Media.xcassets/AppIcon.appiconset/iTunesArtwork.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/drawable-hdpi/ic_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/drawable-hdpi/ic_notification.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/drawable-mdpi/ic_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/drawable-mdpi/ic_notification.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /packages/bcsc-core/android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | -------------------------------------------------------------------------------- /app/__mocks__/react-native-argon2.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line 2 | const argon2 = jest.fn().mockReturnValue({ rawHash: Promise.resolve('1234567890') }) 3 | 4 | export default argon2 5 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/drawable-xhdpi/ic_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/drawable-xhdpi/ic_notification.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/drawable-xxhdpi/ic_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/drawable-xxhdpi/ic_notification.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/drawable-xxxhdpi/ic_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/drawable-xxxhdpi/ic_notification.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/drawable/ic_launcher_play_store.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/drawable/ic_launcher_play_store.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/ios/Media.xcassets/AppIcon.appiconset/iTunesArtwork_Dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/ios/Media.xcassets/AppIcon.appiconset/iTunesArtwork_Dark.png -------------------------------------------------------------------------------- /app/__tests__/components/__snapshots__/HomeHeaderView.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`HomeHeaderView Component renders correctly 1`] = `null`; 4 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/ios/Media.xcassets/AppIcon.appiconset/iTunesArtwork_Tinted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/ios/Media.xcassets/AppIcon.appiconset/iTunesArtwork_Tinted.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bcgov/bc-wallet-mobile/HEAD/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/android/app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #003468 4 | -------------------------------------------------------------------------------- /app/.prettierignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | app.json 3 | ios/ 4 | android/ 5 | node_modules/ 6 | generate-app-package-json.js 7 | src/configs/ledgers/indy/ledgers.json 8 | .gitignore 9 | coverage/ 10 | -------------------------------------------------------------------------------- /packages/bcsc-core/android/gradle.properties: -------------------------------------------------------------------------------- 1 | BcscCore_kotlinVersion=2.0.21 2 | BcscCore_minSdkVersion=24 3 | BcscCore_targetSdkVersion=35 4 | BcscCore_compileSdkVersion=35 5 | BcscCore_ndkVersion=27.1.12297006 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "search.exclude": { 3 | "**/node_modules": true, 4 | }, 5 | "[helm]": { 6 | "editor.formatOnSave": false 7 | }, 8 | "typescript.tsdk": "node_modules/typescript/lib" 9 | } -------------------------------------------------------------------------------- /app/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version 3 | ruby ">= 2.6.10" 4 | gem 'cocoapods', '~> 1.14.3' 5 | gem 'activesupport', '~> 7.0.8' 6 | -------------------------------------------------------------------------------- /app/ios/AriesBifold.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AriesBifold.swift 3 | // AriesBifold 4 | // 5 | // Created by James Ebert on 3/12/21. 6 | // Copyright © 2021 Facebook. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | -------------------------------------------------------------------------------- /app/src/utils/splitSplice.ts: -------------------------------------------------------------------------------- 1 | export const splitSplice = (str: string, index: number, count: number, add: string): string => { 2 | const ar = str.split('') 3 | ar.splice(index, count, add) 4 | return ar.join('') 5 | } 6 | -------------------------------------------------------------------------------- /app/src/theme.ts: -------------------------------------------------------------------------------- 1 | import { BCSCTheme } from '@bcsc-theme/theme' 2 | import { BCWalletTheme } from '@bcwallet-theme/theme' 3 | import { ITheme } from '@bifold/core' 4 | 5 | export const themes: ITheme[] = [BCWalletTheme, BCSCTheme] 6 | -------------------------------------------------------------------------------- /app/__mocks__/@react-native-firebase/messaging.ts: -------------------------------------------------------------------------------- 1 | const messaging = jest.fn().mockReturnValue({ 2 | setBackgroundMessageHandler: jest.fn(), 3 | onMessage: jest.fn(), 4 | requestPermission: jest.fn(), 5 | }) 6 | 7 | export default messaging 8 | -------------------------------------------------------------------------------- /app/android/settings-gradle.lockfile: -------------------------------------------------------------------------------- 1 | # This is a Gradle generated file for dependency locking. 2 | # Manual edits can break the build and are not advised. 3 | # This file is expected to be part of source control. 4 | empty=incomingCatalogForLibs0 5 | -------------------------------------------------------------------------------- /app/__mocks__/react-native-keychain.ts: -------------------------------------------------------------------------------- 1 | const ACCESS_CONTROL = jest.fn() 2 | const ACCESSIBLE = jest.fn() 3 | const SECURITY_LEVEL = jest.fn() 4 | const STORAGE_TYPE = jest.fn() 5 | 6 | export { ACCESSIBLE, ACCESS_CONTROL, SECURITY_LEVEL, STORAGE_TYPE } 7 | -------------------------------------------------------------------------------- /app/__mocks__/react-native-bcsc-core.ts: -------------------------------------------------------------------------------- 1 | const getAccount = jest.fn() 2 | const removeAccount = jest.fn() 3 | const createQuickLoginJWT = jest.fn() 4 | const decodePayload = jest.fn() 5 | 6 | export { createQuickLoginJWT, decodePayload, getAccount, removeAccount } 7 | -------------------------------------------------------------------------------- /app/src/configs/ledgers/indy/ledgers.ts: -------------------------------------------------------------------------------- 1 | import { IndyVdrPoolConfig } from '@credo-ts/indy-vdr' 2 | 3 | import _ledgers from './ledgers.json' 4 | 5 | const filePersistedLedgers: IndyVdrPoolConfig[] = _ledgers ?? [] 6 | 7 | export default filePersistedLedgers 8 | -------------------------------------------------------------------------------- /packages/bcsc-core/ios/BcscCore-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | // Add this line for new architecture support when needed 5 | #ifdef RCT_NEW_ARCH_ENABLED 6 | #import "RNBcscCoreSpec.h" 7 | #endif -------------------------------------------------------------------------------- /packages/bcsc-core/android/src/newarch/BcscCoreSpec.kt: -------------------------------------------------------------------------------- 1 | package com.bcsccore 2 | 3 | import com.facebook.react.bridge.ReactApplicationContext 4 | 5 | abstract class BcscCoreSpec internal constructor(context: ReactApplicationContext) : 6 | NativeBcscCoreSpec(context) { 7 | } 8 | -------------------------------------------------------------------------------- /scripts/gpublish/README.md: -------------------------------------------------------------------------------- 1 | This is a script to help publish to the Google Play API so that 2 | we have an automated end-to-end CICD pipeline. 3 | 4 | When you make changes, make sure it publish it to npm with 5 | `npm publish`. 6 | 7 | Usage: 8 | 9 | `npx @bcgov/gpublish` 10 | -------------------------------------------------------------------------------- /app/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'BCWallet' 2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) 3 | include ':app' 4 | includeBuild('../node_modules/@react-native/gradle-plugin') 5 | -------------------------------------------------------------------------------- /scripts/makeauthkey.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eau -o pipefail 3 | 4 | KEY_PATH=$RUNNER_TEMP/AuthKey.p9 5 | 6 | echo ">> Build API AuthKey Starting... 🤞" 7 | 8 | echo "${AUTHKEY_P8}" >"${KEY_PATH}" 9 | md5 "$KEY_PATH" 10 | 11 | echo ">> Build API AuthKey Finished. 🤗" 12 | 13 | exit 0 14 | -------------------------------------------------------------------------------- /app/__mocks__/@react-native-async-storage/async-storage.js: -------------------------------------------------------------------------------- 1 | const store = {} 2 | 3 | export default class AsyncStorage { 4 | static getItem = (key) => { 5 | return store[key] 6 | } 7 | 8 | static setItem = (key, value) => { 9 | store[key] = value 10 | 11 | return null 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.svg' { 2 | import { SvgProps } from 'react-native-svg' 3 | const content: React.FC 4 | export default content 5 | } 6 | 7 | declare module '*.png' 8 | declare module '*.jpg' 9 | declare module '*.jpeg' 10 | 11 | declare module 'react-native-argon2' 12 | -------------------------------------------------------------------------------- /app/ios/AriesBifold/AriesBifold.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-all.zip 4 | networkTimeout=10000 5 | alidateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /app/ios/AriesBifold.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /update-lock-files: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(git --exec-path)/git-sh-setup" 3 | 4 | require_clean_work_tree "update lock files" 5 | 6 | yarn install 7 | ( cd app/ios; pod install ) 8 | ( cd app/android; ./gradlew app:dependencies --write-locks ) 9 | 10 | git add . 11 | git commit -sm "chore:update lock files" --no-verify 12 | -------------------------------------------------------------------------------- /app/ios/AriesBifold.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/bcsc-core/react-native.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {import('@react-native-community/cli-types').UserDependencyConfig} 3 | */ 4 | module.exports = { 5 | dependency: { 6 | platforms: { 7 | android: { 8 | cmakeListsPath: 'generated/jni/CMakeLists.txt', 9 | }, 10 | }, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /app/ios/AriesBifold.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /COMPLIANCE.yaml: -------------------------------------------------------------------------------- 1 | name: compliance 2 | description: | 3 | This document is used to track a projects PIA and STRA 4 | compliance. 5 | spec: 6 | - name: PIA 7 | status: in-progress 8 | last-updated: '2021-09-27T21:00:51.557Z' 9 | - name: STRA 10 | status: in-progress 11 | last-updated: '2021-09-27T21:00:51.557Z' 12 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/__mocks__/react-native-volume-manager.ts: -------------------------------------------------------------------------------- 1 | export const VolumeManager = { 2 | getVolume: jest.fn().mockResolvedValue({ volume: 0.5 }), 3 | setVolume: jest.fn().mockResolvedValue({ volume: 0.5 }), 4 | showNativeVolumeUI: jest.fn().mockResolvedValue({ show: true }), 5 | addVolumeListener: jest.fn(() => ({ 6 | remove: jest.fn(), 7 | })), 8 | } 9 | -------------------------------------------------------------------------------- /app/__mocks__/react-native-permissions.ts: -------------------------------------------------------------------------------- 1 | const check = jest.fn() 2 | const request = jest.fn().mockResolvedValue('not-granted') 3 | 4 | const PERMISSIONS = { 5 | ANDROID: { 6 | POST_NOTIFICATIONS: 'POST_NOTIFICATIONS', 7 | }, 8 | } 9 | 10 | const RESULTS = { 11 | GRANTED: 'granted', 12 | } 13 | 14 | export { PERMISSIONS, RESULTS, check, request } 15 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/features/deep-linking/index.ts: -------------------------------------------------------------------------------- 1 | export { DeepLinkViewModel } from './DeepLinkViewModel' 2 | export { DeepLinkViewModelProvider, useDeepLinkViewModel } from './DeepLinkViewModelContext' 3 | export { DeepLinkService, type DeepLinkHandler, type DeepLinkPayload } from './services/deep-linking' 4 | export { useHasPendingDeepLink } from './useHasPendingDeepLink' 5 | -------------------------------------------------------------------------------- /scripts/bump_ios_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -xaou pipefail 3 | 4 | # /usr/libexec/PlistBuddy \ 5 | # -c "Set :CFBundleVersion ${GITHUB_RUN_NUMBER}" "$1" 6 | 7 | # /usr/libexec/PlistBuddy \ 8 | # -c "Set :CFBundleShortVersionString ${VERSION_STRING}" "$1" 9 | 10 | agvtool new-version ${CURRENT_PROJECT_VERSION} 11 | agvtool new-marketing-version ${MARKETING_VERSION} 12 | -------------------------------------------------------------------------------- /app/__mocks__/@pexip/infinity-api.ts: -------------------------------------------------------------------------------- 1 | export const requestToken = jest.fn() 2 | export const refreshToken = jest.fn() 3 | export const callsWebrtcParticipant = jest.fn() 4 | export const newCandidate = jest.fn() 5 | export const disconnectCall = jest.fn() 6 | export const withPin = jest.fn((fetcher: any) => fetcher) 7 | export const withToken = jest.fn((fetcher: any) => fetcher) 8 | -------------------------------------------------------------------------------- /app/__tests__/screens/__snapshots__/TransferQRDisplayScreen.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`TransferQRDisplay renders correctly 1`] = ` 4 | 14 | `; 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2-feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Feature request" 3 | about: Suggest a new feature for BC Wallet 4 | --- 5 | 6 | 7 | ### Description of feature / user story 8 | 9 | ### Acceptance Criteria 10 | 11 | ### Wireframes or relevant image assets / links -------------------------------------------------------------------------------- /app/src/localization/index.ts: -------------------------------------------------------------------------------- 1 | import { translationResources } from '@bifold/core' 2 | import merge from 'lodash.merge' 3 | 4 | import en from './en' 5 | import fr from './fr' 6 | import ptBr from './pt-br' 7 | 8 | export const localization = merge({}, translationResources, { 9 | en: { translation: en }, 10 | fr: { translation: fr }, 11 | 'pt-BR': { translation: ptBr }, 12 | }) 13 | -------------------------------------------------------------------------------- /packages/bcsc-core/ios/JOSEException.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Common.swift 3 | // jose 4 | // 5 | // Created by marcosc on 2016-12-08. 6 | // Copyright © 2016 idim. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct JOSEException: Error { 12 | let description: String 13 | init(_ description: String) { 14 | self.description = description 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/__mocks__/@react-native-clipboard/clipboard.js: -------------------------------------------------------------------------------- 1 | // @react-native-clipboard/clipboard mock 2 | module.exports = { 3 | getString: jest.fn(() => Promise.resolve('mocked clipboard content')), // eslint-disable-line no-undef 4 | setString: jest.fn(() => Promise.resolve()), // eslint-disable-line no-undef 5 | hasString: jest.fn(() => Promise.resolve(true)), // eslint-disable-line no-undef 6 | } 7 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/__tests__/contexts/auth.ts: -------------------------------------------------------------------------------- 1 | const authContext = { 2 | getWalletSecret: jest.fn(), 3 | removeSavedWalletSecret: jest.fn(), 4 | checkWalletPIN: jest.fn(), 5 | commitWalletToKeychain: jest.fn(), 6 | setPIN: jest.fn(), 7 | isBiometricsActive: jest.fn(), 8 | disableBiometrics: jest.fn(), 9 | rekeyWallet: jest.fn(), 10 | lockOutUser: jest.fn(), 11 | } 12 | 13 | export default authContext 14 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/api/workflow/key-rotation.workflow.ts: -------------------------------------------------------------------------------- 1 | export async function checkKeyStatus() { 2 | // keys can be rotated for the following reasons: 3 | // - 90 days have passed 4 | // - key is not valid 5 | } 6 | export async function rotateKeys() { 7 | // get current keys 8 | // get new keys 9 | // end date old keys 10 | // save new keys to device 11 | // save new keys to server 12 | // check new keys work 13 | } 14 | -------------------------------------------------------------------------------- /app/__mocks__/custom/@react-navigation/core.ts: -------------------------------------------------------------------------------- 1 | const navigate = jest.fn() 2 | 3 | const navigation = { 4 | navigate, 5 | setOptions: jest.fn(), 6 | getParent: jest.fn(() => ({ 7 | navigate, 8 | })), 9 | getState: jest.fn(() => ({ 10 | index: jest.fn(), 11 | })), 12 | goBack: jest.fn(), 13 | pop: jest.fn(), 14 | reset: jest.fn(), 15 | } 16 | 17 | const useNavigation = () => { 18 | return navigation 19 | } 20 | 21 | export { useNavigation } 22 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rules: { 3 | 'signed-off-by': [2, 'always', 'Signed-off-by:'], 4 | 'type-enum': [2, 'always', [ 5 | 'feat', 6 | 'fix', 7 | 'docs', 8 | 'style', 9 | 'refactor', 10 | 'perf', 11 | 'test', 12 | 'chore', 13 | 'revert', 14 | ]], 15 | 'type-case': [2, 'always', 'lower-case'], 16 | 'type-empty': [2, 'never'], 17 | 'subject-empty': [2, 'never'], 18 | }, 19 | } 20 | -------------------------------------------------------------------------------- /app/__mocks__/react-native-screenguard.ts: -------------------------------------------------------------------------------- 1 | // Mock for react-native-screenguard 2 | const ScreenGuardModule = { 3 | register: jest.fn(), 4 | unregister: jest.fn(), 5 | registerScreenRecording: jest.fn(), 6 | unregisterScreenRecording: jest.fn(), 7 | enableBlurScreen: jest.fn(), 8 | disableBlurScreen: jest.fn(), 9 | addListener: jest.fn(() => ({ 10 | remove: jest.fn(), 11 | })), 12 | removeListeners: jest.fn(), 13 | } 14 | 15 | export default ScreenGuardModule 16 | -------------------------------------------------------------------------------- /app/android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1-bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Bug report" 3 | about: Create a report to help us improve 4 | --- 5 | 6 | 7 | 8 | ### Description of problem 9 | 10 | ### Expected behavior 11 | 12 | ### Steps to reproduce 13 | 14 | ### Screenshots and/or log output 15 | 16 | ### Environment 17 | 18 | Build #: 19 | 20 | Android Device Model: 21 | 22 | iOS Device Model: 23 | 24 | ### Workaround 25 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/features/verify/live-call/utils/formatCallTime.ts: -------------------------------------------------------------------------------- 1 | export const formatCallTime = (seconds: number): string => { 2 | const hours = Math.floor(seconds / 3600) 3 | const minutes = Math.floor((seconds % 3600) / 60) 4 | const remainingSeconds = seconds % 60 5 | 6 | if (hours > 0) { 7 | return `${hours}:${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}` 8 | } else { 9 | return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}` 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/ios/.xcode.env: -------------------------------------------------------------------------------- 1 | # This `.xcode.env` file is versioned and is used to source the environment 2 | # used when running script phases inside Xcode. 3 | # To customize your local environment, you can create an `.xcode.env.local` 4 | # file that is not versioned. 5 | # NODE_BINARY variable contains the PATH to the node executable. 6 | # 7 | # Customize the NODE_BINARY variable here. 8 | # For example, to use nvm with brew, add the following line 9 | # . "$(brew --prefix nvm)/nvm.sh" --no-use 10 | export NODE_BINARY=$(command -v node) 11 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/features/verify/live-call/utils/clearTimeoutIfExists.ts: -------------------------------------------------------------------------------- 1 | export const clearTimeoutIfExists = (timeoutRef: React.MutableRefObject) => { 2 | if (timeoutRef.current) { 3 | clearTimeout(timeoutRef.current) 4 | timeoutRef.current = null 5 | } 6 | } 7 | 8 | export const clearIntervalIfExists = (intervalRef: React.MutableRefObject) => { 9 | if (intervalRef.current) { 10 | clearInterval(intervalRef.current) 11 | intervalRef.current = null 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/__mocks__/react-native-incall-manager.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | start: jest.fn(), 3 | stop: jest.fn(), 4 | setKeepScreenOn: jest.fn(), 5 | setSpeakerphoneOn: jest.fn(), 6 | setForceSpeakerphoneOn: jest.fn(), 7 | setMicrophoneMute: jest.fn(), 8 | checkRecordPermission: jest.fn().mockResolvedValue('granted'), 9 | checkCameraPermission: jest.fn().mockResolvedValue('granted'), 10 | requestRecordPermission: jest.fn().mockResolvedValue('granted'), 11 | requestCameraPermission: jest.fn().mockResolvedValue('granted'), 12 | } 13 | -------------------------------------------------------------------------------- /app/__tests__/screens/__snapshots__/ServiceLoginScreen.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`ServiceLogin renders correctly 1`] = ` 4 | 20 | 23 | 24 | `; 25 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/features/deep-linking/useHasPendingDeepLink.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react' 2 | import { useDeepLinkViewModel } from './DeepLinkViewModelContext' 3 | 4 | export const useHasPendingDeepLink = () => { 5 | const viewModel = useDeepLinkViewModel() 6 | 7 | const [hasPending, setHasPending] = useState(viewModel.hasPendingDeepLink) 8 | 9 | useEffect(() => { 10 | return viewModel.onPendingStateChange((pending) => { 11 | setHasPending(pending) 12 | }) 13 | }, [viewModel]) 14 | 15 | return hasPending 16 | } 17 | -------------------------------------------------------------------------------- /scripts/gpublish/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bcgov/gpublish", 3 | "version": "1.2.0", 4 | "description": "Scripts to help automate Google Play API access", 5 | "main": "index.js", 6 | "bin": "index.js", 7 | "files": [ 8 | "index.js", 9 | "package.json", 10 | "README.md" 11 | ], 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1" 14 | }, 15 | "author": "Jason C. Leach > Build Provisioning Profile... 🤞" 7 | echo ">> Provisioning Profile Home = ${PP_DIR}" 8 | 9 | UUID=$(/usr/libexec/plistbuddy -c Print:UUID /dev/stdin <<< `echo "${PROVISIONING_PROFILE}" | base64 -d | security cms -D`) 10 | base64 -d <<< "${PROVISIONING_PROFILE}" >${UUID}.mobileprovision 11 | md5 "${UUID}.mobileprovision" 12 | mkdir -p "${PP_DIR}" 13 | cp ${UUID}.mobileprovision "${PP_DIR}/" 14 | 15 | echo ">> Build Provisioning Profile. 🤗" 16 | 17 | exit 18 | -------------------------------------------------------------------------------- /app/src/utils/expiration.ts: -------------------------------------------------------------------------------- 1 | export const expirationOverrideInMinutes = ( 2 | enabledAt: Date, 3 | autoDisableRemoteLoggingIntervalInMinutes: number 4 | ): number => { 5 | const now = Date.now() 6 | const enabledAtTime = enabledAt.getTime() 7 | const autoDisableIntervalInMilliseconds = autoDisableRemoteLoggingIntervalInMinutes * 60000 8 | 9 | if (enabledAtTime < now - autoDisableIntervalInMilliseconds) { 10 | return 0 11 | } 12 | 13 | const diffInMinutes = Math.floor((now - enabledAtTime) / 60000) 14 | return autoDisableRemoteLoggingIntervalInMinutes - diffInMinutes 15 | } 16 | -------------------------------------------------------------------------------- /app/src/events/alertEvents.ts: -------------------------------------------------------------------------------- 1 | // Alert interaction types (display, action ie: 'OK' button pressed) 2 | export enum AlertInteractionEvent { 3 | ALERT_DISPLAY = 'alert_display', 4 | ALERT_ACTION = 'alert_action', 5 | } 6 | 7 | /** 8 | * Alert events 9 | * 10 | * TODO (MD): combine all Android and iOS alert events from `ias-android` and `ias-ios` current code ie: AlertKey.java... 11 | * and add all mapped values from `bcsc_alerts.json` to translation files 12 | */ 13 | export enum AlertEvent { 14 | ADD_CARD_CAMERA_BROKEN = 'add_card_camera_broken', 15 | // ... other alert events go here 16 | } 17 | -------------------------------------------------------------------------------- /app/src/utils/mediator.ts: -------------------------------------------------------------------------------- 1 | import { Agent, MediatorPickupStrategy } from '@credo-ts/core' 2 | 3 | export const batchPickup = async (agent: Agent): Promise => { 4 | try { 5 | for (let i = 0; i < 2; i++) { 6 | agent.config.logger.debug(`Batch pickup attempt ${i + 1}`) 7 | agent.mediationRecipient.initiateMessagePickup(undefined, MediatorPickupStrategy.Implicit) 8 | await new Promise((resolve) => setTimeout(resolve, 50)) // wait for .05 seconds before next pickup 9 | } 10 | } catch (error) { 11 | agent.config.logger.error(`Error during batch pickup: ${error}`) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /.yarn/patches/@credo-ts-indy-vdr-npm-0.5.17-aa0b05041f.patch: -------------------------------------------------------------------------------- 1 | diff --git a/build/pool/IndyVdrPool.js b/build/pool/IndyVdrPool.js 2 | index 7c157d6754dcba7526100f67dbed3c86b335b0cc..56437364edcb3d16e998fb4766d7b14cae63430f 100644 3 | --- a/build/pool/IndyVdrPool.js 4 | +++ b/build/pool/IndyVdrPool.js 5 | @@ -17,7 +17,7 @@ class IndyVdrPool { 6 | } 7 | connect() { 8 | if (this._pool) { 9 | - throw new error_1.IndyVdrError('Cannot connect to pool, already connected.'); 10 | + return; 11 | } 12 | this._pool = new indy_vdr_shared_1.PoolCreate({ 13 | parameters: { 14 | -------------------------------------------------------------------------------- /packages/bcsc-core/android/src/main/java/com/bcsccore/bcsc-file-port/src/main/java/com/bcsccore/fileport/decryption/DecryptionException.java: -------------------------------------------------------------------------------- 1 | package com.bcsccore.fileport.decryption; 2 | 3 | /** 4 | * Exception thrown when file decryption fails 5 | */ 6 | public class DecryptionException extends Exception { 7 | 8 | public DecryptionException(String message) { 9 | super(message); 10 | } 11 | 12 | public DecryptionException(String message, Throwable cause) { 13 | super(message, cause); 14 | } 15 | 16 | public DecryptionException(Throwable cause) { 17 | super(cause); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/__tests__/components/EmptyList.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import EmptyList from '@bcwallet-theme/components/EmptyList' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | 7 | describe('EmptyList Component', () => { 8 | beforeEach(() => { 9 | jest.useFakeTimers() 10 | }) 11 | 12 | afterEach(() => { 13 | jest.useRealTimers() 14 | }) 15 | test('renders correctly', () => { 16 | const tree = render( 17 | 18 | 19 | 20 | ) 21 | expect(tree).toMatchSnapshot() 22 | }) 23 | }) 24 | -------------------------------------------------------------------------------- /app/src/bcwallet-theme/features/tours/hooks/tour-image-dimensions.ts: -------------------------------------------------------------------------------- 1 | import { useWindowDimensions } from 'react-native' 2 | 3 | const useTourImageDimensions = () => { 4 | const { width: windowWidth, height: windowHeight } = useWindowDimensions() // NOSONAR 5 | const totalHorizontalImagePadding = 90 6 | const portraitMode = windowHeight > windowWidth 7 | const imageWidth = Math.floor( 8 | portraitMode ? windowWidth - totalHorizontalImagePadding : windowHeight - totalHorizontalImagePadding 9 | ) 10 | const imageHeight = Math.floor(imageWidth * 0.66) 11 | 12 | return { imageWidth, imageHeight } 13 | } 14 | 15 | export default useTourImageDimensions 16 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/api/hooks/withAccountGuard.ts: -------------------------------------------------------------------------------- 1 | import { getAccount } from 'react-native-bcsc-core' 2 | 3 | /** 4 | * This is a wrapper function to centralize checking for an account before executing a function. 5 | * 6 | * @param fn Function that `withAccount` will wrap, which requires an account to be present. 7 | * @returns The executed function with the account passed as an argument. 8 | */ 9 | export const withAccount = async (fn: (account: any) => Promise): Promise => { 10 | const account = await getAccount() 11 | if (!account) { 12 | throw new Error('No account found. Please register first.') 13 | } 14 | 15 | return fn(account) 16 | } 17 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/features/webview/MainWebViewScreen.tsx: -------------------------------------------------------------------------------- 1 | import { BCSCMainStackParams, BCSCScreens } from '@/bcsc-theme/types/navigators' 2 | import { RouteProp } from '@react-navigation/native' 3 | import React from 'react' 4 | import { WebViewContent } from './WebViewContent' 5 | 6 | interface MainWebViewScreenProps { 7 | route: RouteProp 8 | } 9 | 10 | const MainWebViewScreen: React.FC = ({ route }) => { 11 | const { url, injectedJavascript } = route.params 12 | 13 | return 14 | } 15 | 16 | export { MainWebViewScreen } 17 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/features/webview/VerifyWebViewScreen.tsx: -------------------------------------------------------------------------------- 1 | import { BCSCScreens, BCSCVerifyStackParams } from '@/bcsc-theme/types/navigators' 2 | import { RouteProp } from '@react-navigation/native' 3 | import React from 'react' 4 | import { WebViewContent } from './WebViewContent' 5 | 6 | interface VerifyWebViewScreenProps { 7 | route: RouteProp 8 | } 9 | 10 | const VerifyWebViewScreen: React.FC = ({ route }) => { 11 | const { url, injectedJavascript } = route.params 12 | 13 | return 14 | } 15 | 16 | export { VerifyWebViewScreen } 17 | -------------------------------------------------------------------------------- /packages/bcsc-core/README.md: -------------------------------------------------------------------------------- 1 | # react-native-bcsc-core 2 | 3 | Functionality and data access for legacy bcsc application. 4 | 5 | ## Installation 6 | 7 | ```sh 8 | npm install react-native-bcsc-core 9 | ``` 10 | 11 | ## Usage 12 | 13 | 14 | ```js 15 | import { multiply } from 'react-native-bcsc-core'; 16 | 17 | // ... 18 | 19 | const result = multiply(3, 7); 20 | ``` 21 | 22 | 23 | ## Contributing 24 | 25 | See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow. 26 | 27 | ## License 28 | 29 | MIT 30 | 31 | --- 32 | 33 | Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob) 34 | -------------------------------------------------------------------------------- /.yarn/patches/@hyperledger-indy-vdr-shared-npm-0.2.2-b989282fc6.patch: -------------------------------------------------------------------------------- 1 | diff --git a/build/types/IndyVdr.d.ts b/build/types/IndyVdr.d.ts 2 | index 99f5d50a851462c8c41e52ceb49795feebce0b4e..3aa7890e1f3c422daa6ec82fd6b42d0b924d18b5 100644 3 | --- a/build/types/IndyVdr.d.ts 4 | +++ b/build/types/IndyVdr.d.ts 5 | @@ -11,6 +11,11 @@ export interface IndyVdr { 6 | setCacheDirectory(options: { 7 | path: string; 8 | }): void; 9 | + setLedgerTxnCache(options: { 10 | + capacity: number; 11 | + expiry_offset_ms: number; 12 | + path?: string; 13 | + }): void; 14 | setDefaultLogger(): void; 15 | setProtocolVersion(options: { 16 | version: number; 17 | -------------------------------------------------------------------------------- /.yarn/patches/@animo-id-pex-npm-4.1.1-alpha.0-f29edfffa2.patch: -------------------------------------------------------------------------------- 1 | diff --git a/package.json b/package.json 2 | index becc91ce9fd93bb8ec6d6fc401fa208274c5b0a7..b881d21b40012126fb1901b1e5940fafecce90dc 100644 3 | --- a/package.json 4 | +++ b/package.json 5 | @@ -20,7 +20,6 @@ 6 | "DIF" 7 | ], 8 | "scripts": { 9 | - "preinstall": "npx only-allow pnpm", 10 | "build": "run-s build:*", 11 | "build:generateFieldv1Schema": "ts-json-schema-generator -p resources/schema-generator-interfaces/filterV1.ts > resources/FilterV1.schema.json", 12 | "build:generateFieldv2Schema": "ts-json-schema-generator -p resources/schema-generator-interfaces/filterV2.ts > resources/FilterV2.schema.json", 13 | -------------------------------------------------------------------------------- /app/android/app/src/main/res/layout/launch_screen.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 15 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/types/cards.ts: -------------------------------------------------------------------------------- 1 | export enum BCSCCardType { 2 | Combined = 'BC Services Card Combo', // IAS compatible value 3 | Photo = 'BC Services Card Photo', // IAS compatible value 4 | NonPhoto = 'BC Services Card Non-Photo', // IAS compatible value 5 | Other = 'Non BC Services Card(s)', // Local value for non-BCSC cards (IAS value is undefined) 6 | None = 'None', // Local value when no card is present 7 | } 8 | 9 | export enum BCSCCardProcess { 10 | BCSCPhoto = 'IDIM L3 Remote BCSC Photo Identity Verification', 11 | BCSCNonPhoto = 'IDIM L3 Remote BCSC Non-Photo Identity Verification', 12 | NonBCSC = 'IDIM L3 Remote Non-BCSC Identity Verification', 13 | None = 'N/A', 14 | } 15 | -------------------------------------------------------------------------------- /export-options-bcw.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | teamID 6 | L796QSLV3E 7 | method 8 | app-store 9 | signingStyle 10 | manual 11 | stripSwiftSymbols 12 | 13 | uploadBitcode 14 | 15 | uploadSymbols 16 | 17 | provisioningProfiles 18 | 19 | ca.bc.gov.BCWallet 20 | 7a6bfbda-8f83-441e-b709-b57b1863b627 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/android/app/build_defs.bzl: -------------------------------------------------------------------------------- 1 | """Helper definitions to glob .aar and .jar targets""" 2 | 3 | def create_aar_targets(aarfiles): 4 | for aarfile in aarfiles: 5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")] 6 | lib_deps.append(":" + name) 7 | android_prebuilt_aar( 8 | name = name, 9 | aar = aarfile, 10 | ) 11 | 12 | def create_jar_targets(jarfiles): 13 | for jarfile in jarfiles: 14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")] 15 | lib_deps.append(":" + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | -------------------------------------------------------------------------------- /.yarn/patches/@sphereon-pex-npm-5.0.0-unstable.24-921df3a8ac.patch: -------------------------------------------------------------------------------- 1 | diff --git a/package.json b/package.json 2 | index 9ab8d81ceb3728acd0e38a00af46881f93e68584..935b51ac44ad3a641c4e3b5006b681994d456143 100644 3 | --- a/package.json 4 | +++ b/package.json 5 | @@ -67,7 +67,6 @@ 6 | "printWidth": 150 7 | }, 8 | "scripts": { 9 | - "preinstall": "npx only-allow pnpm", 10 | "build": "run-s build:*", 11 | "build:generateFieldv1Schema": "ts-json-schema-generator -p resources/schema-generator-interfaces/filterV1.ts > resources/FilterV1.schema.json", 12 | "build:generateFieldv2Schema": "ts-json-schema-generator -p resources/schema-generator-interfaces/filterV2.ts > resources/FilterV2.schema.json", 13 | -------------------------------------------------------------------------------- /export-options-sa.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | teamID 6 | L796QSLV3E 7 | method 8 | app-store-connect 9 | signingStyle 10 | manual 11 | stripSwiftSymbols 12 | 13 | uploadBitcode 14 | 15 | uploadSymbols 16 | 17 | provisioningProfiles 18 | 19 | ca.bc.gov.iddev.servicescard 20 | 4f031630-16e4-4f8d-8723-a3d920577416 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/features/webview/OnboardingWebViewScreen.tsx: -------------------------------------------------------------------------------- 1 | import { BCSCOnboardingStackParams, BCSCScreens } from '@/bcsc-theme/types/navigators' 2 | import { RouteProp } from '@react-navigation/native' 3 | import React from 'react' 4 | import { WebViewContent } from './WebViewContent' 5 | 6 | interface OnboardingWebViewScreenProps { 7 | route: RouteProp 8 | } 9 | 10 | const OnboardingWebViewScreen: React.FC = ({ route }) => { 11 | const { url, injectedJavascript } = route.params 12 | 13 | return 14 | } 15 | 16 | export { OnboardingWebViewScreen } 17 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Summary of Changes 2 | 3 | Replace this text with a high-level summary of the changes included in this PR. 4 | 5 | # Testing Instructions 6 | 7 | Replace this text with detailed instructions on how to test the changes included in this PR. 8 | 9 | # Acceptance Criteria 10 | 11 | Replace this text with the acceptance criteria that must be met for this PR to be approved. 12 | 13 | # Screenshots, videos, or gifs 14 | 15 | Replace this text with embedded media for UI changes if they are included in this PR. If there are none, simply enter N/A 16 | 17 | # Related Issues 18 | 19 | Replace this text with tagged issue #'s that are relevant to this PR. If there are none, simply enter N/A 20 | -------------------------------------------------------------------------------- /app/src/assets/img/credentialIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/__tests__/components/HomeHeaderView.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import HomeHeaderView from '@bcwallet-theme/components/HomeHeaderView' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | 7 | describe('HomeHeaderView Component', () => { 8 | beforeEach(() => { 9 | jest.clearAllMocks() 10 | jest.useFakeTimers() 11 | }) 12 | 13 | afterEach(() => { 14 | jest.useRealTimers() 15 | }) 16 | 17 | test('renders correctly', () => { 18 | const tree = render( 19 | 20 | 21 | 22 | ) 23 | expect(tree).toMatchSnapshot() 24 | }) 25 | }) 26 | -------------------------------------------------------------------------------- /app/src/utils/analytics/analytics-singleton.ts: -------------------------------------------------------------------------------- 1 | import { AnalyticsTracker } from './analytics-tracker' 2 | 3 | const ANALYTICS_SINGLEAPP_NAMESPACE = 'singleapp_client' 4 | const ANALYTICS_SINGLEAPP_ENDPOINT = __DEV__ ? 'localhost:9090' : '' // TODO (MD): Add production endpoint 5 | 6 | declare global { 7 | // eslint-disable-next-line no-var 8 | var __ANALYTICS_TRACKER_SINGLETON__: AnalyticsTracker | undefined 9 | } 10 | 11 | // Hot-reload safe singleton instance of AnalyticsTracker 12 | export const Analytics = 13 | globalThis.__ANALYTICS_TRACKER_SINGLETON__ ?? 14 | (globalThis.__ANALYTICS_TRACKER_SINGLETON__ = new AnalyticsTracker( 15 | ANALYTICS_SINGLEAPP_NAMESPACE, 16 | ANALYTICS_SINGLEAPP_ENDPOINT 17 | )) 18 | -------------------------------------------------------------------------------- /app/src/bcwallet-theme/features/tours/index.ts: -------------------------------------------------------------------------------- 1 | import { BaseTourID, TourStep } from '@bifold/core' 2 | 3 | import { credentialOfferTourSteps } from './CredentialOfferTourSteps' 4 | import { credentialsTourSteps } from './CredentialsTourSteps' 5 | import { homeTourSteps } from './HomeTourSteps' 6 | import { proofRequestTourSteps } from './ProofRequestTourSteps' 7 | 8 | // to extend, add " | BCTourID" where BCTourID has tour IDs specific to BC Wallet 9 | export type TourID = BaseTourID 10 | 11 | type Tours = { 12 | [key in TourID]: TourStep[] 13 | } 14 | 15 | const tours: Tours = { 16 | homeTourSteps, 17 | credentialsTourSteps, 18 | credentialOfferTourSteps, 19 | proofRequestTourSteps, 20 | } 21 | 22 | export default tours 23 | -------------------------------------------------------------------------------- /app/__tests__/components/AddCredentialButton.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import AddCredentialButton from '@bcwallet-theme/components/AddCredentialButton' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | 7 | describe('AddCredentialButton Component', () => { 8 | beforeEach(() => { 9 | jest.clearAllMocks() 10 | jest.useFakeTimers() 11 | }) 12 | 13 | afterEach(() => { 14 | jest.useRealTimers() 15 | }) 16 | test('renders correctly', () => { 17 | const tree = render( 18 | 19 | 20 | 21 | ) 22 | expect(tree).toMatchSnapshot() 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /app/__tests__/components/ErrorTextBox.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { BasicAppContext } from '../../__mocks__/helpers/app' 5 | import ErrorTextBox from '../../src/components/ErrorTextBox' 6 | 7 | describe('ErrorTextBox Component', () => { 8 | beforeEach(() => { 9 | jest.clearAllMocks() 10 | jest.useFakeTimers() 11 | }) 12 | 13 | afterEach(() => { 14 | jest.useRealTimers() 15 | }) 16 | test('renders correctly', () => { 17 | const tree = render( 18 | 19 | Lorem ipsum sit dolar 20 | 21 | ) 22 | 23 | expect(tree).toMatchSnapshot() 24 | }) 25 | }) 26 | -------------------------------------------------------------------------------- /app/__tests__/screens/EditNicknameScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { BasicAppContext } from '../../__mocks__/helpers/app' 5 | import EditNicknameScreen from '../../src/bcsc-theme/features/account/EditNicknameScreen' 6 | 7 | describe('EditNickname', () => { 8 | beforeEach(() => { 9 | jest.clearAllMocks() 10 | jest.useFakeTimers() 11 | }) 12 | 13 | afterEach(() => { 14 | jest.useRealTimers() 15 | }) 16 | 17 | it('renders correctly', () => { 18 | const tree = render( 19 | 20 | 21 | 22 | ) 23 | 24 | expect(tree).toMatchSnapshot() 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /app/src/Root.tsx: -------------------------------------------------------------------------------- 1 | import { BCState, Mode } from '@/store' 2 | import BCSCRootStack from '@bcsc-theme/navigators/RootStack' 3 | import { RootStack as BCWalletRootStack, useStore } from '@bifold/core' 4 | import { BCSCApiClientProvider } from './bcsc-theme/contexts/BCSCApiClientContext' 5 | import { BCSCLoadingProvider } from './bcsc-theme/contexts/BCSCLoadingContext' 6 | 7 | const Root: React.FC = () => { 8 | const [store] = useStore() 9 | 10 | return store.mode === Mode.BCSC ? ( 11 | 12 | 13 | 14 | 15 | 16 | ) : ( 17 | 18 | ) 19 | } 20 | 21 | export default Root 22 | -------------------------------------------------------------------------------- /app/__tests__/screens/NicknameAccountScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { BasicAppContext } from '../../__mocks__/helpers/app' 5 | import NicknameAccountScreen from '../../src/bcsc-theme/features/account/NicknameAccountScreen' 6 | 7 | describe('NicknameAccount', () => { 8 | beforeEach(() => { 9 | jest.clearAllMocks() 10 | jest.useFakeTimers() 11 | }) 12 | 13 | afterEach(() => { 14 | jest.useRealTimers() 15 | }) 16 | 17 | it('renders correctly', () => { 18 | const tree = render( 19 | 20 | 21 | 22 | ) 23 | 24 | expect(tree).toMatchSnapshot() 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/navigators/stack-utils.ts: -------------------------------------------------------------------------------- 1 | import { StackNavigationOptions } from '@react-navigation/stack' 2 | import { createHeaderWithoutBanner } from '../components/HeaderWithBanner' 3 | 4 | /** 5 | * Returns default screen options for modal presentations. 6 | * 7 | * @param {string} title - The title of the modal screen. 8 | * @returns {*} {StackNavigationOptions} The default modal screen options. 9 | */ 10 | export function getDefaultModalOptions(title?: string): StackNavigationOptions { 11 | return { 12 | presentation: 'modal', 13 | headerShown: true, 14 | headerLeft: () => null, 15 | title: title, 16 | headerShadowVisible: false, 17 | header: createHeaderWithoutBanner, 18 | gestureEnabled: true, 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/__mocks__/custom/react-native-camera.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Constants = { 4 | device: {}, 5 | torch: { 6 | on: 'on', 7 | off: 'off', 8 | auto: 'auto', 9 | }, 10 | isActive: false, 11 | codeScanner: {}, 12 | } 13 | 14 | class Camera extends React.Component { 15 | static Constants = Constants 16 | render() { 17 | return null 18 | } 19 | } 20 | 21 | Camera.Constants = Constants 22 | const useCameraDevice = jest.fn() 23 | const useCodeScanner = jest.fn() 24 | const useCameraFormat = jest.fn() 25 | const useCameraPermission = jest.fn(() => ({ 26 | hasPermission: true, 27 | requestPermission: jest.fn(), 28 | })) 29 | export { Camera, useCameraDevice, useCameraFormat, useCameraPermission, useCodeScanner } 30 | -------------------------------------------------------------------------------- /app/__tests__/screens/MismatchedSerialScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { BasicAppContext } from '../../__mocks__/helpers/app' 5 | import MismatchedSerialScreen from '../../src/bcsc-theme/features/verify/MismatchedSerialScreen' 6 | 7 | describe('MismatchedSerial', () => { 8 | beforeEach(() => { 9 | jest.clearAllMocks() 10 | jest.useFakeTimers() 11 | }) 12 | 13 | afterEach(() => { 14 | jest.useRealTimers() 15 | }) 16 | 17 | it('renders correctly', () => { 18 | const tree = render( 19 | 20 | 21 | 22 | ) 23 | 24 | expect(tree).toMatchSnapshot() 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /packages/bcsc-core/android/src/main/java/com/bcsccore/bcsc-keypair-port/core/exceptions/KeypairGenerationException.java: -------------------------------------------------------------------------------- 1 | package com.bcsccore.keypair.core.exceptions; 2 | 3 | /** 4 | * Specific exception for key pair generation failures. 5 | * This exception is thrown when Android KeyStore operations fail 6 | * during key pair generation or retrieval. 7 | */ 8 | public class KeypairGenerationException extends BcscException { 9 | 10 | /** 11 | * Create a keypair generation exception with a developer message. 12 | * @param devMessage the message describing what went wrong during key generation 13 | */ 14 | public KeypairGenerationException(String devMessage) { 15 | super(AlertKey.ADD_CARD_KEYPAIR_GENERATION, devMessage); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /.sonarcloud.properties: -------------------------------------------------------------------------------- 1 | # 2 | # SPDX-License-Identifier: Apache-2.0 3 | # 4 | 5 | # Path to sources 6 | sonar.sources=. 7 | sonar.exclusions=**/CredentialOfferTourSteps.tsx,**/CredentialsTourSteps.tsx,**/HomeTourSteps.tsx,**/ProofRequestTourSteps.tsx,**/localization/**/index.ts,**/packages/bcsc-core/ios/**,**/packages/bcsc-core/android/**,**/__tests__/**/*.ts,**/__tests__/**/*.tsx,**/__mocks__/**/*.ts,**/__mocks__/**/*.tsx,**/*.test.ts,**/*.test.tsx 8 | 9 | #sonar.inclusions= 10 | 11 | # Path to tests 12 | #sonar.tests= 13 | #sonar.test.exclusions= 14 | #sonar.test.inclusions= 15 | 16 | # Source encoding 17 | #sonar.sourceEncoding=UTF-8 18 | 19 | # Exclusions for copy-paste detection 20 | sonar.cpd.exclusions=**/__tests__/**/*,**/__mocks__/**/*,**/request-templates.ts 21 | -------------------------------------------------------------------------------- /app/__tests__/screens/TransferQRDisplayScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { BasicAppContext } from '../../__mocks__/helpers/app' 5 | import TransferQRDisplayScreen from '../../src/bcsc-theme/features/account-transfer/TransferQRDisplayScreen' 6 | 7 | describe('TransferQRDisplay', () => { 8 | beforeEach(() => { 9 | jest.clearAllMocks() 10 | jest.useFakeTimers() 11 | }) 12 | 13 | afterEach(() => { 14 | jest.useRealTimers() 15 | }) 16 | 17 | it('renders correctly', () => { 18 | const tree = render( 19 | 20 | 21 | 22 | ) 23 | 24 | expect(tree).toMatchSnapshot() 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /app/__tests__/screens/VerificationSuccessScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { BasicAppContext } from '../../__mocks__/helpers/app' 5 | import VerificationSuccessScreen from '../../src/bcsc-theme/features/verify/VerificationSuccessScreen' 6 | 7 | describe('VerificationSuccess', () => { 8 | beforeEach(() => { 9 | jest.clearAllMocks() 10 | jest.useFakeTimers() 11 | }) 12 | 13 | afterEach(() => { 14 | jest.useRealTimers() 15 | }) 16 | 17 | it('renders correctly', () => { 18 | const tree = render( 19 | 20 | 21 | 22 | ) 23 | 24 | expect(tree).toMatchSnapshot() 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /app/src/utils/links.ts: -------------------------------------------------------------------------------- 1 | import { BCSC_APPLE_STORE_URL, BCSC_GOOGLE_PLAY_STORE_URL } from '@/constants' 2 | import { Linking, Platform } from 'react-native' 3 | 4 | export const openLink = async (url: string) => { 5 | // Only `https://` is allowed. Update manifest as needed. 6 | const supported = await Linking.canOpenURL(url) 7 | 8 | if (supported) { 9 | // Will open in device browser. 10 | await Linking.openURL(url) 11 | } 12 | } 13 | 14 | /** 15 | * Get the BCSC App Store URL based on the platform. 16 | * 17 | * @returns {*} {string} The BCSC app store URL. 18 | */ 19 | export const getBCSCAppStoreUrl = (): string => { 20 | if (Platform.OS === 'ios') { 21 | return BCSC_APPLE_STORE_URL 22 | } 23 | 24 | return BCSC_GOOGLE_PLAY_STORE_URL 25 | } 26 | -------------------------------------------------------------------------------- /packages/bcsc-core/android/src/main/java/com/bcsccore/bcsc-file-port/src/main/java/com/bcsccore/fileport/decryption/FileDecryptor.java: -------------------------------------------------------------------------------- 1 | package com.bcsccore.fileport.decryption; 2 | 3 | /** 4 | * Interface for decrypting file content 5 | */ 6 | public interface FileDecryptor { 7 | 8 | /** 9 | * Decrypt encrypted file content 10 | * @param encryptedContent the encrypted byte array 11 | * @return decrypted content as string 12 | * @throws DecryptionException if decryption fails 13 | */ 14 | String decrypt(byte[] encryptedContent) throws DecryptionException; 15 | 16 | /** 17 | * Check if decryption is available/initialized 18 | * @return true if decryptor is ready to use 19 | */ 20 | boolean isAvailable(); 21 | } 22 | -------------------------------------------------------------------------------- /app/__tests__/screens/TransferInformationScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { BasicAppContext } from '../../__mocks__/helpers/app' 5 | import TransferInformationScreen from '../../src/bcsc-theme/features/account-transfer/TransferInformationScreen' 6 | 7 | describe('TransferInformation', () => { 8 | beforeEach(() => { 9 | jest.clearAllMocks() 10 | jest.useFakeTimers() 11 | }) 12 | 13 | afterEach(() => { 14 | jest.useRealTimers() 15 | }) 16 | 17 | it('renders correctly', () => { 18 | const tree = render( 19 | 20 | 21 | 22 | ) 23 | 24 | expect(tree).toMatchSnapshot() 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3-help.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Help request" 3 | about: Let us know where you're getting stuck 4 | --- 5 | 6 | 7 | 8 | ### Description of problem 9 | 10 | ### Steps taken to solve 11 | 12 | - [ ] Read through docs in this repo and (bifold-wallet)[github.com/openwallet-foundation/bifold-wallet] 13 | - [ ] Posted in OpenWallet Foundation Discord 14 | 15 | ### Screenshots and/or log output 16 | 17 | ### Development Environment 18 | 19 | - [ ] Android Emulator 20 | - [ ] Android Device 21 | - [ ] iOS Simulator 22 | - [ ] iOS Device 23 | - [ ] Mac (Intel) 24 | - [ ] Mac (Apple Silicon) 25 | - [ ] Linux 26 | - [ ] Windows 27 | -------------------------------------------------------------------------------- /app/__tests__/screens/TransferInstructionsScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { BasicAppContext } from '../../__mocks__/helpers/app' 5 | import TransferInstructionsScreen from '../../src/bcsc-theme/features/account-transfer/TransferInstructionsScreen' 6 | 7 | describe('TransferInstructions', () => { 8 | beforeEach(() => { 9 | jest.clearAllMocks() 10 | jest.useFakeTimers() 11 | }) 12 | 13 | afterEach(() => { 14 | jest.useRealTimers() 15 | }) 16 | 17 | it('renders correctly', () => { 18 | const tree = render( 19 | 20 | 21 | 22 | ) 23 | 24 | expect(tree).toMatchSnapshot() 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /devops/charts/loki-logstack/templates/routes.yaml: -------------------------------------------------------------------------------- 1 | kind: Route 2 | apiVersion: route.openshift.io/v1 3 | metadata: 4 | name: {{include "logstack.fullname" .}}-proxy 5 | labels: {{- include "logstack.labels" . | nindent 4}} 6 | annotations: {{- toYaml .Values.route.annotations | nindent 4}} 7 | spec: 8 | {{- if .Values.route.host }} 9 | host: {{ .Values.route.host }} 10 | {{- end }} 11 | to: 12 | kind: Service 13 | name: {{include "logstack.fullname" .}}-proxy 14 | weight: 100 15 | port: 16 | {{- range $name, $port := .Values.services.proxy }} 17 | {{- if eq .name "http" }} 18 | targetPort: {{ .port }} 19 | {{- end }} 20 | {{- end }} 21 | tls: 22 | termination: edge 23 | insecureEdgeTerminationPolicy: Redirect 24 | wildcardPolicy: None 25 | -------------------------------------------------------------------------------- /app/__tests__/screens/AccountSetupSelectionScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { BasicAppContext } from '../../__mocks__/helpers/app' 5 | import AccountSetupSelectionScreen from '../../src/bcsc-theme/features/account-transfer/AccountSetupSelectionScreen' 6 | 7 | describe('AccountSetupSelection', () => { 8 | beforeEach(() => { 9 | jest.clearAllMocks() 10 | jest.useFakeTimers() 11 | }) 12 | 13 | afterEach(() => { 14 | jest.useRealTimers() 15 | }) 16 | 17 | it('renders correctly', () => { 18 | const tree = render( 19 | 20 | 21 | 22 | ) 23 | 24 | expect(tree).toMatchSnapshot() 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /app/src/hooks/useDebounce.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react' 2 | 3 | /** 4 | * A custom React hook that debounces a value. 5 | * 6 | * @template T The type of the value to be debounced. 7 | * @param {T} value The value to be debounced. 8 | * @param {number} delayMs The debounce delay in milliseconds. 9 | * @returns {*} {T} The debounced value. 10 | */ 11 | export const useDebounce = (value: T, delayMs: number) => { 12 | const [debouncedValue, setDebouncedValue] = useState(value) 13 | 14 | useEffect(() => { 15 | const debounceHandler = setTimeout(() => setDebouncedValue(value), delayMs) 16 | 17 | // Cleanup timeout if value or delay changes 18 | return () => clearTimeout(debounceHandler) 19 | }, [value, delayMs]) 20 | 21 | return debouncedValue 22 | } 23 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/features/settings/MainContactUsScreen.tsx: -------------------------------------------------------------------------------- 1 | import { BCSCMainStackParams, BCSCScreens } from '@/bcsc-theme/types/navigators' 2 | import { ScreenWrapper } from '@bifold/core' 3 | import { StackNavigationProp } from '@react-navigation/stack' 4 | import React from 'react' 5 | import { ContactUsContent } from './ContactUsContent' 6 | 7 | type MainContactUsScreenProps = { 8 | navigation: StackNavigationProp 9 | } 10 | 11 | /** 12 | * Contact Us screen for the Main stack. 13 | * Wraps ContactUsContent with proper navigation typing. 14 | */ 15 | export const MainContactUsScreen: React.FC = () => { 16 | return ( 17 | 18 | 19 | 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /app/__tests__/screens/RemoveAccountConfirmationScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { BasicAppContext } from '../../__mocks__/helpers/app' 5 | import RemoveAccountConfirmationScreen from '../../src/bcsc-theme/features/account/RemoveAccountConfirmationScreen' 6 | 7 | describe('RemoveAccountConfirmation', () => { 8 | beforeEach(() => { 9 | jest.clearAllMocks() 10 | jest.useFakeTimers() 11 | }) 12 | 13 | afterEach(() => { 14 | jest.useRealTimers() 15 | }) 16 | 17 | it('renders correctly', () => { 18 | const tree = render( 19 | 20 | 21 | 22 | ) 23 | 24 | expect(tree).toMatchSnapshot() 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /app/__tests__/screens/__snapshots__/VerificationMethodSelectionScreen.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`VerificationMethodSelection renders correctly 1`] = ` 4 | 23 | 32 | 33 | 34 | 35 | `; 36 | -------------------------------------------------------------------------------- /app/__tests__/screens/AccountRenewalFinalWarningScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { BasicAppContext } from '../../__mocks__/helpers/app' 5 | import { AccountRenewalFinalWarningScreen } from '../../src/bcsc-theme/features/account/AccountRenewalFinalWarningScreen' 6 | 7 | describe('AccountRenewalFinalWarning', () => { 8 | beforeEach(() => { 9 | jest.clearAllMocks() 10 | jest.useFakeTimers() 11 | }) 12 | 13 | afterEach(() => { 14 | jest.useRealTimers() 15 | }) 16 | 17 | it('renders correctly', () => { 18 | const tree = render( 19 | 20 | 21 | 22 | ) 23 | 24 | expect(tree).toMatchSnapshot() 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/features/settings/VerifyContactUsScreen.tsx: -------------------------------------------------------------------------------- 1 | import { BCSCScreens, BCSCVerifyStackParams } from '@/bcsc-theme/types/navigators' 2 | import { ScreenWrapper } from '@bifold/core' 3 | import { StackNavigationProp } from '@react-navigation/stack' 4 | import React from 'react' 5 | import { ContactUsContent } from './ContactUsContent' 6 | 7 | type VerifyContactUsScreenProps = { 8 | navigation: StackNavigationProp 9 | } 10 | 11 | /** 12 | * Contact Us screen for the Verify stack. 13 | * Wraps ContactUsContent with proper navigation typing. 14 | */ 15 | export const VerifyContactUsScreen: React.FC = () => { 16 | return ( 17 | 18 | 19 | 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/features/deep-linking/DeepLinkViewModelContext.tsx: -------------------------------------------------------------------------------- 1 | import React, { createContext, useContext } from 'react' 2 | import { DeepLinkViewModel } from './DeepLinkViewModel' 3 | 4 | const DeepLinkViewModelContext = createContext(null) 5 | 6 | export const DeepLinkViewModelProvider: React.FC<{ 7 | viewModel: DeepLinkViewModel 8 | children: React.ReactNode 9 | }> = ({ viewModel, children }) => { 10 | return {children} 11 | } 12 | 13 | export const useDeepLinkViewModel = () => { 14 | const context = useContext(DeepLinkViewModelContext) 15 | if (!context) { 16 | throw new Error('useDeepLinkViewModel must be used within a DeepLinkViewModelProvider') 17 | } 18 | 19 | return context 20 | } 21 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/utils/account-utils.ts: -------------------------------------------------------------------------------- 1 | import { formStringLengths } from '@/constants' 2 | import { BCState } from '@/store' 3 | 4 | // Helper function to check if a nickname exists 5 | export const hasNickname = (state: BCState, nickname: string): boolean => { 6 | return state.bcsc.nicknames.includes(nickname) 7 | } 8 | 9 | export const getNicknameValidationErrorKey = (state: BCState, nickname: string): string | null => { 10 | if (nickname.length < formStringLengths.minimumLength) { 11 | return 'BCSC.NicknameAccount.EmptyNameTitle' 12 | } 13 | 14 | if (nickname.length > formStringLengths.maximumLength) { 15 | return 'BCSC.NicknameAccount.CharCountTitle' 16 | } 17 | 18 | if (hasNickname(state, nickname)) { 19 | return 'BCSC.NicknameAccount.NameAlreadyExists' 20 | } 21 | 22 | return null 23 | } 24 | -------------------------------------------------------------------------------- /app/__tests__/screens/MainWebViewScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { BasicAppContext } from '../../__mocks__/helpers/app' 5 | import { MainWebViewScreen } from '../../src/bcsc-theme/features/webview/MainWebViewScreen' 6 | 7 | describe('MainWebView', () => { 8 | beforeEach(() => { 9 | jest.clearAllMocks() 10 | jest.useFakeTimers() 11 | }) 12 | 13 | afterEach(() => { 14 | jest.useRealTimers() 15 | }) 16 | 17 | it('renders correctly', () => { 18 | const route = { params: { url: 'https://example.com', title: 'Test' } } 19 | const tree = render( 20 | 21 | 22 | 23 | ) 24 | 25 | expect(tree).toMatchSnapshot() 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /.github/workflows/scanner.yml: -------------------------------------------------------------------------------- 1 | name: Virus Scanner 2 | permissions: 3 | contents: read 4 | 5 | on: 6 | push: 7 | branches: [main] 8 | pull_request: 9 | branches: [main] 10 | 11 | jobs: 12 | shai-hulud-scan: 13 | runs-on: ubuntu-22.04 14 | name: Scan code for Shai-hulud virus 15 | steps: 16 | - name: Checkout bc-wallet-mobile 17 | uses: actions/checkout@v4 18 | with: 19 | path: bc-wallet-mobile 20 | 21 | - name: Checkout Shai-hulud scanner 22 | uses: actions/checkout@v4 23 | with: 24 | repository: CyberDracula/shai-hulud-2-scanner 25 | path: shai-hulud-2-scanner 26 | 27 | - name: Run Shai-hulud virus scanner 28 | working-directory: shai-hulud-2-scanner 29 | run: node scan.js --fail-on=critical ../bc-wallet-mobile 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/__tests__/screens/RemoteLogWarning.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { BasicAppContext } from '../../__mocks__/helpers/app' 5 | import RemoteLogWarning from '../../src/screens/RemoteLogWarning' 6 | 7 | jest.mock('react-native-splash-screen', () => ({})) 8 | 9 | describe('RemoteLogWarning Screen', () => { 10 | beforeEach(() => { 11 | jest.useFakeTimers() 12 | }) 13 | 14 | afterEach(() => { 15 | jest.clearAllMocks() 16 | jest.useRealTimers() 17 | }) 18 | 19 | test('screen renders correctly', () => { 20 | const tree = render( 21 | 22 | 23 | 24 | ) 25 | 26 | expect(tree).toMatchSnapshot() 27 | }) 28 | }) 29 | -------------------------------------------------------------------------------- /app/__tests__/screens/VerifyWebViewScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { BasicAppContext } from '../../__mocks__/helpers/app' 5 | import { VerifyWebViewScreen } from '../../src/bcsc-theme/features/webview/VerifyWebViewScreen' 6 | 7 | describe('VerifyWebView', () => { 8 | beforeEach(() => { 9 | jest.clearAllMocks() 10 | jest.useFakeTimers() 11 | }) 12 | 13 | afterEach(() => { 14 | jest.useRealTimers() 15 | }) 16 | 17 | it('renders correctly', () => { 18 | const route = { params: { url: 'https://example.com', title: 'Test' } } 19 | const tree = render( 20 | 21 | 22 | 23 | ) 24 | 25 | expect(tree).toMatchSnapshot() 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /app/__mocks__/react-i18next.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 4 | const reactI18Next: any = jest.createMockFromModule('react-i18next') 5 | 6 | reactI18Next.useTranslation = () => { 7 | return { 8 | t: (str: string) => str, 9 | i18n: { 10 | changeLanguage: () => new Promise(() => {}), 11 | language: 'en', 12 | t: (str: string) => str, 13 | }, 14 | } 15 | } 16 | 17 | reactI18Next.Trans = ({ children, i18nKey }: { children?: React.ReactNode; i18nKey?: string }) => { 18 | return React.createElement('span', {}, children || i18nKey || '') 19 | } 20 | reactI18Next.Trans.displayName = 'Trans' 21 | 22 | reactI18Next.initReactI18next = { 23 | type: '3rdParty', 24 | init: jest.fn(), 25 | } 26 | 27 | module.exports = reactI18Next 28 | 29 | export default {} 30 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## How to Contribute 2 | 3 | Government employees, public and members of the private sector are encouraged to contribute to the repository by **forking and submitting a pull request**. 4 | 5 | (If you are new to GitHub, you might start with a [basic tutorial](https://help.github.com/articles/set-up-git) and check out a more detailed guide to [pull requests](https://help.github.com/articles/using-pull-requests/).) 6 | 7 | Pull requests will be evaluated by the repository guardians on a schedule and if deemed beneficial will be committed to the master. 8 | 9 | All contributors retain the original copyright to their stuff, but by contributing to this project, you grant a world-wide, royalty-free, perpetual, irrevocable, non-exclusive, transferable license to all users **under the terms of the license under which this project is distributed.** 10 | -------------------------------------------------------------------------------- /app/__tests__/components/LoadingIcon.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { BasicAppContext } from '../../__mocks__/helpers/app' 5 | import LoadingIcon from '../../src/components/LoadingIcon' 6 | 7 | describe('LoadingIcon Component', () => { 8 | beforeEach(() => { 9 | jest.clearAllMocks() 10 | jest.useFakeTimers() 11 | }) 12 | 13 | afterEach(() => { 14 | jest.useRealTimers() 15 | }) 16 | test('renders correctly', () => { 17 | const size = 50 // arbitrary 18 | const color = '#333' // arbitrary 19 | const active = true // arbitrary 20 | const tree = render( 21 | 22 | 23 | 24 | ) 25 | expect(tree).toMatchSnapshot() 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /options-dev.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | compileBitcode 6 | 7 | destination 8 | export 9 | method 10 | development 11 | provisioningProfiles 12 | 13 | ca.bc.gov.BCWallet 14 | BC Wallet - Development Jason 15 | 16 | signingCertificate 17 | 67D6BA0FEC3E43792AABC24ED686303A9E3BB23F 18 | signingStyle 19 | manual 20 | stripSwiftSymbols 21 | 22 | teamID 23 | L796QSLV3E 24 | thinning 25 | <none> 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/__tests__/components/__snapshots__/LoadingIcon.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`LoadingIcon Component renders correctly 1`] = ` 4 | 16 | 37 |  38 | 39 | 40 | `; 41 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/features/account/components/AccountField.tsx: -------------------------------------------------------------------------------- 1 | import { ThemedText, useTheme } from '@bifold/core' 2 | import React from 'react' 3 | import { StyleSheet, View, ViewStyle } from 'react-native' 4 | 5 | export interface AccountFieldProps { 6 | label: string 7 | value: string 8 | style?: ViewStyle 9 | } 10 | 11 | const AccountField: React.FC = ({ label, value, style }) => { 12 | const { Spacing } = useTheme() 13 | 14 | const styles = StyleSheet.create({ 15 | label: { 16 | marginBottom: Spacing.xs, 17 | }, 18 | }) 19 | 20 | return ( 21 | 22 | 23 | {label} 24 | 25 | {value} 26 | 27 | ) 28 | } 29 | 30 | export default AccountField 31 | -------------------------------------------------------------------------------- /app/babel.config.js: -------------------------------------------------------------------------------- 1 | const presets = ['module:@react-native/babel-preset'] 2 | const plugins = [ 3 | [ 4 | 'module-resolver', 5 | { 6 | root: ['.'], 7 | extensions: ['.tsx', 'ts'], 8 | alias: { 9 | '@': './src', 10 | '@assets': './src/assets', 11 | '@bcwallet-theme': './src/bcwallet-theme', 12 | '@bcsc-theme': './src/bcsc-theme', 13 | '@components': './src/components', 14 | '@events': './src/events', 15 | '@hooks': './src/hooks', 16 | '@screens': './src/screens', 17 | '@services': './src/services', 18 | '@types': './src/types', 19 | '@utils': './src/utils', 20 | }, 21 | }, 22 | ], 23 | ] 24 | 25 | if (process.env['ENV'] === 'prod') { 26 | plugins.push('transform-remove-console') 27 | } 28 | 29 | module.exports = { 30 | presets, 31 | plugins, 32 | } 33 | -------------------------------------------------------------------------------- /app/__mocks__/react-native-tcp-socket/index.ts: -------------------------------------------------------------------------------- 1 | let aNode: any = undefined 2 | 3 | const ports = { 4 | connect: 8001, 5 | error: 8002, 6 | timeout: 8003, 7 | } 8 | 9 | const on = (event: any, cb: any) => { 10 | switch (event) { 11 | case 'timeout': 12 | if (aNode.port === ports.timeout) { 13 | cb() 14 | } 15 | break 16 | case 'error': 17 | if (aNode.port === ports.error) { 18 | cb() 19 | } 20 | break 21 | default: 22 | break 23 | } 24 | } 25 | 26 | const client = { 27 | on, 28 | destroy: jest.fn(), 29 | setTimeout: jest.fn(), 30 | removeAllListeners: jest.fn(), 31 | } 32 | 33 | const createConnection = jest.fn((node, cb) => { 34 | aNode = node 35 | 36 | if (node.port === ports.connect) { 37 | cb() 38 | } 39 | 40 | return client 41 | }) 42 | 43 | export default { createConnection } 44 | -------------------------------------------------------------------------------- /app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig-base.json", 3 | "compilerOptions": { 4 | "outDir": "./lib", 5 | "declaration": true, 6 | "skipLibCheck": true, 7 | "baseUrl": ".", 8 | "paths": { 9 | "@/*": ["src/*"], 10 | "@assets/*": ["src/assets/*"], 11 | "@bcwallet-theme/*": ["src/bcwallet-theme/*"], 12 | "@bcsc-theme/*": ["src/bcsc-theme/*"], 13 | "@components/*": ["src/components/*"], 14 | "@events/*": ["src/events/*"], 15 | "@hooks/*": ["src/hooks/*"], 16 | "@screens/*": ["src/screens/*"], 17 | "@services/*": ["src/services/*"], 18 | "@types/*": ["src/types/*"], 19 | "@utils/*": ["src/utils/*"], 20 | "react-native-bcsc-core": ["../packages/bcsc-core/src"] 21 | } 22 | }, 23 | "exclude": ["node_modules", "metro.config.js", "babel.config.js", "jest.config.js", "jestSetup.js"] 24 | } 25 | -------------------------------------------------------------------------------- /app/__mocks__/@react-navigation/core.ts: -------------------------------------------------------------------------------- 1 | const navigate = jest.fn() 2 | const dispatch = jest.fn() 3 | const replace = jest.fn() 4 | const navigation = { 5 | __timestamp: process.hrtime(), 6 | navigate, 7 | replace, 8 | setOptions: jest.fn(), 9 | getParent: () => { 10 | return { 11 | navigate, 12 | dispatch, 13 | replace, 14 | } 15 | }, 16 | getState: jest.fn(() => ({ 17 | index: jest.fn(), 18 | })), 19 | goBack: jest.fn(), 20 | pop: jest.fn(), 21 | reset: jest.fn(), 22 | isFocused: () => true, 23 | dispatch, 24 | } 25 | 26 | const useNavigation = () => { 27 | return navigation 28 | } 29 | 30 | const useIsFocused = () => { 31 | return true 32 | } 33 | 34 | const CommonActions = { 35 | navigate: jest.fn(), 36 | reset: jest.fn(), 37 | goBack: jest.fn(), 38 | } 39 | 40 | export { CommonActions, useIsFocused, useNavigation } 41 | -------------------------------------------------------------------------------- /packages/bcsc-core/android/src/main/java/com/bcsccore/bcsc-file-port/src/main/java/com/bcsccore/fileport/encryption/Encryption.java: -------------------------------------------------------------------------------- 1 | package com.bcsccore.fileport.encryption; 2 | 3 | /** 4 | * Interface for encryption/decryption operations. 5 | * This is a self-contained copy of the original BCSC Encryption interface. 6 | */ 7 | public interface Encryption { 8 | /** 9 | * Encrypt a message string into bytes 10 | * @param message The string to encrypt 11 | * @return Encrypted bytes 12 | * @throws Exception if encryption fails 13 | */ 14 | byte[] encrypt(String message) throws Exception; 15 | 16 | /** 17 | * Decrypt bytes back to a string 18 | * @param bytes The encrypted bytes to decrypt 19 | * @return Decrypted string 20 | * @throws Exception if decryption fails 21 | */ 22 | String decrypt(byte[] bytes) throws Exception; 23 | } 24 | -------------------------------------------------------------------------------- /app/__tests__/screens/ResidentialAddressScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { BasicAppContext } from '../../__mocks__/helpers/app' 5 | import { ResidentialAddressScreen } from '../../src/bcsc-theme/features/verify/ResidentialAddressScreen' 6 | 7 | describe('ResidentialAddress', () => { 8 | let mockNavigation: any 9 | let mockRoute: any 10 | 11 | beforeEach(() => { 12 | jest.clearAllMocks() 13 | jest.useFakeTimers() 14 | }) 15 | 16 | afterEach(() => { 17 | jest.useRealTimers() 18 | }) 19 | 20 | it('renders correctly', () => { 21 | const tree = render( 22 | 23 | 24 | 25 | ) 26 | 27 | expect(tree).toMatchSnapshot() 28 | }) 29 | }) 30 | -------------------------------------------------------------------------------- /packages/bcsc-core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "rootDir": ".", 4 | "paths": { 5 | "react-native-bcsc-core": ["./src/index"] 6 | }, 7 | "allowUnreachableCode": false, 8 | "allowUnusedLabels": false, 9 | "esModuleInterop": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "jsx": "react-jsx", 12 | "lib": ["ESNext"], 13 | "module": "ESNext", 14 | "moduleResolution": "bundler", 15 | "noEmit": true, 16 | "noFallthroughCasesInSwitch": true, 17 | "noImplicitReturns": true, 18 | "noImplicitUseStrict": false, 19 | "noStrictGenericChecks": false, 20 | "noUncheckedIndexedAccess": true, 21 | "noUnusedLocals": true, 22 | "noUnusedParameters": true, 23 | "resolveJsonModule": true, 24 | "skipLibCheck": true, 25 | "strict": true, 26 | "target": "ESNext", 27 | "verbatimModuleSyntax": true 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/__tests__/screens/ScanSerialScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import ScanSerialScreen from '../../src/bcsc-theme/features/verify/ScanSerialScreen' 7 | 8 | describe('ScanSerial', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/SetupStepsScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import SetupStepsScreen from '../../src/bcsc-theme/features/verify/SetupStepsScreen' 7 | 8 | describe('SetupSteps', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/android/app/.idea/modules/app.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/__tests__/screens/SecureAppScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import { SecureAppScreen } from '../../src/bcsc-theme/features/onboarding/SecureAppScreen' 7 | 8 | describe('SecureApp', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/StartCallScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import StartCallScreen from '../../src/bcsc-theme/features/verify/live-call/StartCallScreen' 7 | 8 | describe('StartCall', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/src/bcwallet-theme/components/AddCredentialButton.tsx: -------------------------------------------------------------------------------- 1 | import { ButtonLocation, IconButton, testIdWithKey } from '@bifold/core' 2 | import React, { useCallback } from 'react' 3 | import { useTranslation } from 'react-i18next' 4 | import { DeviceEventEmitter } from 'react-native' 5 | 6 | import { BCWalletEventTypes } from '../../events/eventTypes' 7 | 8 | const AddCredentialButton = () => { 9 | const { t } = useTranslation() 10 | 11 | const activateSlider = useCallback(() => { 12 | DeviceEventEmitter.emit(BCWalletEventTypes.ADD_CREDENTIAL_PRESSED, true) 13 | }, []) 14 | 15 | return ( 16 | 23 | ) 24 | } 25 | 26 | export default AddCredentialButton 27 | -------------------------------------------------------------------------------- /app/__tests__/screens/ManualSerialScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import ManualSerialScreen from '../../src/bcsc-theme/features/verify/ManualSerialScreen' 7 | 8 | describe('ManualSerial', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/TermsOfUseScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import { TermsOfUseScreen } from '../../src/bcsc-theme/features/onboarding/TermsOfUseScreen' 7 | 8 | describe('TermsOfUse', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/AccountExpiredScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import { AccountExpiredScreen } from '../../src/bcsc-theme/features/account/AccountExpiredScreen' 7 | 8 | describe('AccountExpired', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/MainSettingsScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import { MainSettingsScreen } from '../../src/bcsc-theme/features/settings/MainSettingsScreen' 7 | 8 | describe('MainSettings', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/src/utils/net-info-config.ts: -------------------------------------------------------------------------------- 1 | import { NetInfoConfiguration } from '@react-native-community/netinfo' 2 | import Config from 'react-native-config' 3 | 4 | // We don't want to actually request an invitation from the mediator 5 | // (which follows the '?') so we just use the base URL 6 | const fullMedUrl = Config.MEDIATOR_URL || '' 7 | let endIndex = fullMedUrl.indexOf('?') 8 | if (endIndex === -1) { 9 | endIndex = fullMedUrl.length 10 | } 11 | const reachabilityUrl = fullMedUrl.substring(0, endIndex) 12 | 13 | // Links to docs: https://github.com/react-native-netinfo/react-native-netinfo/tree/master?tab=readme-ov-file#netinfoconfiguration 14 | export const netInfoConfig: Partial = { 15 | useNativeReachability: false, 16 | reachabilityUrl, 17 | reachabilityTest: async (response: Response) => { 18 | return response.status >= 200 && response.status <= 299 19 | }, 20 | reachabilityRequestTimeout: 3000, 21 | } 22 | -------------------------------------------------------------------------------- /app/__tests__/screens/MainContactUsScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import { MainContactUsScreen } from '../../src/bcsc-theme/features/settings/MainContactUsScreen' 7 | 8 | describe('MainContactUs', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/LiveCallScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import LiveCallScreen from '../../src/bcsc-theme/features/verify/live-call/LiveCallScreen' 7 | 8 | describe('LiveCall', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | 30 | tree.unmount() 31 | }) 32 | }) 33 | -------------------------------------------------------------------------------- /app/__tests__/screens/PendingReviewScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import PendingReviewScreen from '../../src/bcsc-theme/features/verify/send-video/PendingReviewScreen' 7 | 8 | describe('PendingReview', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/VerifyInPersonScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import VerifyInPersonScreen from '../../src/bcsc-theme/features/verify/in-person/VerifyInPersonScreen' 7 | 8 | describe('VerifyInPerson', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/VerifySettingsScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import { VerifySettingsScreen } from '../../src/bcsc-theme/features/settings/VerifySettingsScreen' 7 | 8 | describe('VerifySettings', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /.github/workflows/actions/setup-node/action.yml: -------------------------------------------------------------------------------- 1 | # based on https://github.com/hyperledger/aries-framework-javascript-ext/blob/main/.github/actions/setup-node/action.yml 2 | name: Setup NodeJS 3 | description: Setup NodeJS with caching 4 | author: "timo@animo.id" 5 | 6 | inputs: 7 | node-version: 8 | description: Select the nodejs version to use 9 | required: false 10 | default: "20.19.2" 11 | 12 | runs: 13 | using: composite 14 | steps: 15 | - name: Setup node v${{ inputs.node-version }} 16 | uses: actions/setup-node@v4 17 | with: 18 | node-version: ${{ inputs.node-version }} 19 | registry-url: "https://registry.npmjs.org/" 20 | 21 | - name: Enable corepack and setup Yarn 4.9.2 22 | shell: bash 23 | run: | 24 | corepack enable 25 | corepack prepare yarn@4.9.2 --activate 26 | 27 | - name: Node Version 28 | shell: bash 29 | run: | 30 | node -v && yarn -v 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/IdentitySelectionScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import IdentitySelectionScreen from '../../src/bcsc-theme/features/verify/IdentitySelectionScreen' 7 | 8 | describe('IdentitySelection', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/VerifyContactUsScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import { VerifyContactUsScreen } from '../../src/bcsc-theme/features/settings/VerifyContactUsScreen' 7 | 8 | describe('VerifyContactUs', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/ios/Media.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "iTunesArtwork.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | }, 9 | { 10 | "appearances" : [ 11 | { 12 | "appearance" : "luminosity", 13 | "value" : "dark" 14 | } 15 | ], 16 | "filename" : "iTunesArtwork_Dark.png", 17 | "idiom" : "universal", 18 | "platform" : "ios", 19 | "size" : "1024x1024" 20 | }, 21 | { 22 | "appearances" : [ 23 | { 24 | "appearance" : "luminosity", 25 | "value" : "tinted" 26 | } 27 | ], 28 | "filename" : "iTunesArtwork_Tinted.png", 29 | "idiom" : "universal", 30 | "platform" : "ios", 31 | "size" : "1024x1024" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/__tests__/screens/EvidenceTypeListScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import EvidenceTypeListScreen from '../../src/bcsc-theme/features/verify/non-photo/EvidenceTypeListScreen' 7 | 8 | describe('EvidenceTypeList', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/OnboardingWebViewScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { BasicAppContext } from '../../__mocks__/helpers/app' 5 | import { OnboardingWebViewScreen } from '../../src/bcsc-theme/features/webview/OnboardingWebViewScreen' 6 | 7 | describe('OnboardingWebView', () => { 8 | beforeEach(() => { 9 | jest.clearAllMocks() 10 | jest.useFakeTimers() 11 | }) 12 | 13 | afterEach(() => { 14 | jest.useRealTimers() 15 | }) 16 | 17 | it('renders correctly', () => { 18 | const route = { 19 | key: 'onboarding-webview', 20 | name: 'OnboardingWebView', 21 | params: { url: 'https://example.com', title: 'Test' }, 22 | } as any 23 | const tree = render( 24 | 25 | 26 | 27 | ) 28 | 29 | expect(tree).toMatchSnapshot() 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /app/__tests__/screens/SerialInstructionsScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import SerialInstructionsScreen from '../../src/bcsc-theme/features/verify/SerialInstructionsScreen' 7 | 8 | describe('SerialInstructions', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /PATCH_NOTES.md: -------------------------------------------------------------------------------- 1 | ### Patches 2 | 3 | #### @credo-ts-anoncreds-npm-0.5.13-446ac3168e.patch 4 | Bugs fixed by massaging qualified vs unqualified identifiers 5 | 6 | #### @credo-ts-core-npm-0.5.13-725ab940d0.patch 7 | Fixes three separate issues. One, fix websocket close handling to allow graceful agent shutdown. Two, proper lookup to catch all formats of AnonCreds credentials. Three, dif presentation bug fix for MDoc / OID4VC 8 | 9 | #### @credo-ts-indy-vdr-npm-0.5.13-007d41ad5c.patch 10 | Prevent error on agent restart when same IndyVDR pool is reused. Prevent bug with revocation registry interval 11 | 12 | #### @hyperledger-indy-vdr-react-native-npm-0.2.2-627d424b96.patch 13 | #### @hyperledger-indy-vdr-shared-npm-0.2.2-b989282fc6.patch 14 | Patches adding support for caching by grabbing the 0.4.3 indy-vdr binary from github. There's also some changes to the cpp FFIs 15 | 16 | #### @sphereon-pex-npm-3.3.3-144d9252ec.patch 17 | Fixes local-dev-only bug with yarn install -------------------------------------------------------------------------------- /app/__tests__/screens/ForgetAllPairingsScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import { ForgetAllPairingsScreen } from '../../src/bcsc-theme/features/settings/ForgetAllPairingsScreen' 7 | 8 | describe('ForgetAllPairings', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/SuccessfullySentScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import SuccessfullySentScreen from '../../src/bcsc-theme/features/verify/send-video/SuccessfullySentScreen' 7 | 8 | describe('SuccessfullySent', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/VideoInstructionsScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import VideoInstructionsScreen from '../../src/bcsc-theme/features/verify/send-video/VideoInstructionsScreen' 7 | 8 | describe('VideoInstructions', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/helpers/Utils.test.ts: -------------------------------------------------------------------------------- 1 | import { expirationOverrideInMinutes } from '@utils/expiration' 2 | 3 | import MockDate from 'mockdate' 4 | 5 | jest.useFakeTimers({ legacyFakeTimers: true }) 6 | 7 | describe('Helpers', () => { 8 | beforeAll(() => { 9 | // Set the date to a fixed point in time 10 | MockDate.set('2024-07-09T21:56:44.200Z') 11 | }) 12 | 13 | afterAll(() => { 14 | // Reset the date to the current date after tests 15 | MockDate.reset() 16 | }) 17 | 18 | test('computes expiration override correctly', () => { 19 | const dateInThePast = new Date('2024-07-09T21:23:44.200Z') 20 | const value = expirationOverrideInMinutes(dateInThePast, 60) 21 | 22 | expect(value).toBe(27) 23 | }) 24 | 25 | test('ignore distant expirations ', () => { 26 | const dateInThePast = new Date('2024-07-09T19:23:44.200Z') 27 | const value = expirationOverrideInMinutes(dateInThePast, 60) 28 | 29 | expect(value).toBe(0) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /app/__tests__/screens/BeforeYouCallScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import BeforeYouCallScreen from '../../src/bcsc-theme/features/verify/live-call/BeforeYouCallScreen' 7 | 8 | describe('BeforeYouCall', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/utils/card-utils.ts: -------------------------------------------------------------------------------- 1 | import { BCSCCardProcess, BCSCCardType } from '../types/cards' 2 | 3 | /** 4 | * Get the card process for a given card type. 5 | * 6 | * @throws {Error} If the card type is invalid or None. 7 | * @param {BCSCCardType} cardType - The type of BCSC card. 8 | * @returns {*} {BCSCCardProcess} The corresponding card process. 9 | */ 10 | export function getCardProcessForCardType(cardType: BCSCCardType): BCSCCardProcess | null { 11 | switch (cardType) { 12 | case BCSCCardType.Combined: 13 | return BCSCCardProcess.BCSCPhoto 14 | case BCSCCardType.Photo: 15 | return BCSCCardProcess.BCSCPhoto 16 | case BCSCCardType.NonPhoto: 17 | return BCSCCardProcess.BCSCNonPhoto 18 | case BCSCCardType.Other: 19 | return BCSCCardProcess.NonBCSC 20 | case BCSCCardType.None: 21 | return null // No card -> no card process 22 | default: 23 | return null // Unknown card type -> no card process 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/bcsc-core/turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "pipeline": { 4 | "build:android": { 5 | "env": ["ORG_GRADLE_PROJECT_newArchEnabled"], 6 | "inputs": [ 7 | "package.json", 8 | "android", 9 | "!android/build", 10 | "src/*.ts", 11 | "src/*.tsx", 12 | "example/package.json", 13 | "example/android", 14 | "!example/android/.gradle", 15 | "!example/android/build", 16 | "!example/android/app/build" 17 | ], 18 | "outputs": [] 19 | }, 20 | "build:ios": { 21 | "env": ["RCT_NEW_ARCH_ENABLED"], 22 | "inputs": [ 23 | "package.json", 24 | "*.podspec", 25 | "ios", 26 | "src/*.ts", 27 | "src/*.tsx", 28 | "example/package.json", 29 | "example/ios", 30 | "!example/ios/build", 31 | "!example/ios/Pods" 32 | ], 33 | "outputs": [] 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/__tests__/screens/SettingsPrivacyPolicyScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import { SettingsPrivacyPolicyScreen } from '../../src/bcsc-theme/features/settings/SettingsPrivacyPolicyScreen' 7 | 8 | describe('SettingsPrivacyPolicy', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/VideoTooLongScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import VideoTooLongScreen from '../../src/bcsc-theme/features/verify/send-video/VideoTooLongScreen' 7 | 8 | describe('VideoTooLong', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/CallBusyOrClosedScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import CallBusyOrClosedScreen from '../../src/bcsc-theme/features/verify/live-call/CallBusyOrClosedScreen' 7 | 8 | describe('CallBusyOrClosed', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/OnboardingPrivacyPolicyScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import { OnboardingPrivacyPolicyScreen } from '../../src/bcsc-theme/features/onboarding/OnboardingPrivacyPolicyScreen' 7 | 8 | describe('OnboardingPrivacyPolicy', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/components/TabScreenWrapper.tsx: -------------------------------------------------------------------------------- 1 | import { useTheme } from '@bifold/core' 2 | import React, { ComponentProps, PropsWithChildren } from 'react' 3 | import { ScrollView } from 'react-native' 4 | import { SafeAreaView } from 'react-native-safe-area-context' 5 | 6 | interface TabScreenWrapperProps extends PropsWithChildren { 7 | edges?: ('top' | 'left' | 'right' | 'bottom')[] 8 | scrollViewProps?: ComponentProps 9 | } 10 | 11 | const TabScreenWrapper: React.FC = ({ 12 | edges = ['left', 'right'], 13 | children, 14 | scrollViewProps, 15 | }) => { 16 | const { ColorPalette } = useTheme() 17 | 18 | return ( 19 | 20 | 21 | {children} 22 | 23 | 24 | ) 25 | } 26 | 27 | export default TabScreenWrapper 28 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/features/account/components/AccountPhoto.tsx: -------------------------------------------------------------------------------- 1 | import { useTheme } from '@bifold/core' 2 | import React from 'react' 3 | import { Image, StyleSheet, View } from 'react-native' 4 | 5 | // Placholder for now 6 | const AccountPhoto: React.FC<{ photoUri: string | null }> = ({ photoUri }) => { 7 | const { Spacing, ColorPalette } = useTheme() 8 | 9 | const styles = StyleSheet.create({ 10 | container: { 11 | width: 130, 12 | height: 180, 13 | backgroundColor: ColorPalette.grayscale.lightGrey, 14 | marginBottom: Spacing.md, 15 | justifyContent: 'center', 16 | alignItems: 'center', 17 | overflow: 'hidden', 18 | }, 19 | photo: { 20 | width: '100%', 21 | height: '100%', 22 | resizeMode: 'cover', 23 | }, 24 | }) 25 | 26 | return ( 27 | {photoUri ? : null} 28 | ) 29 | } 30 | 31 | export default AccountPhoto 32 | -------------------------------------------------------------------------------- /app/__tests__/screens/AccountRenewalInformationScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import { AccountRenewalInformationScreen } from '../../src/bcsc-theme/features/account/AccountRenewalInformationScreen' 7 | 8 | describe('AccountRenewalInformation', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/AccountRenewalFirstWarningScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import { AccountRenewalFirstWarningScreen } from '../../src/bcsc-theme/features/account/AccountRenewalFirstWarningScreen' 7 | 8 | describe('AccountRenewalFirstWarning', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/VerificationMethodSelectionScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import VerificationMethodSelectionScreen from '../../src/bcsc-theme/features/verify/VerificationMethodSelectionScreen' 7 | 8 | describe('VerificationMethodSelection', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__mocks__/@react-native-community/netinfo.ts: -------------------------------------------------------------------------------- 1 | const defaultState = { 2 | type: 'cellular', 3 | isConnected: true, 4 | isInternetReachable: true, 5 | details: { 6 | isConnectionExpensive: true, 7 | cellularGeneration: '3g', 8 | }, 9 | } 10 | 11 | const NetInfoStateType = { 12 | unknown: 'unknown', 13 | none: 'none', 14 | cellular: 'cellular', 15 | wifi: 'wifi', 16 | bluetooth: 'bluetooth', 17 | ethernet: 'ethernet', 18 | wimax: 'wimax', 19 | vpn: 'vpn', 20 | other: 'other', 21 | } 22 | 23 | const RNCNetInfoMock = { 24 | NetInfoStateType, 25 | configure: jest.fn(), 26 | fetch: jest.fn(), 27 | refresh: jest.fn(), 28 | addEventListener: jest.fn(), 29 | useNetInfo: jest.fn(), 30 | } 31 | 32 | RNCNetInfoMock.fetch.mockResolvedValue(defaultState) 33 | RNCNetInfoMock.refresh.mockResolvedValue(defaultState) 34 | RNCNetInfoMock.useNetInfo.mockReturnValue(defaultState) 35 | RNCNetInfoMock.addEventListener.mockReturnValue(jest.fn()) 36 | 37 | export default RNCNetInfoMock 38 | -------------------------------------------------------------------------------- /app/__tests__/screens/DualIdentificationRequiredScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import DualIdentificationRequiredScreen from '../../src/bcsc-theme/features/verify/non-photo/DualIdentificationRequiredScreen' 7 | 8 | describe('DualIdentificationRequired', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/ios/AriesBifoldTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | UIAppFonts 24 | 25 | MaterialIcons.ttf 26 | MaterialCommunityIcons.ttf 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/__tests__/screens/PhotoReviewScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import PhotoReviewScreen from '../../src/bcsc-theme/features/verify/PhotoReviewScreen' 7 | 8 | describe('PhotoReview', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const route = { params: { photoPath: 'file://test.jpg' } } 23 | const tree = render( 24 | 25 | 26 | 27 | ) 28 | 29 | expect(tree).toMatchSnapshot() 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /packages/bcsc-core/android/src/main/java/com/bcsccore/bcsc-keypair-port/core/exceptions/AlertKey.java: -------------------------------------------------------------------------------- 1 | package com.bcsccore.keypair.core.exceptions; 2 | 3 | /** 4 | * Enumeration of error keys used for identifying different types of exceptions. 5 | * This is a simplified version of the original AlertKey enum with only the 6 | * keys needed for key pair operations. 7 | */ 8 | public enum AlertKey { 9 | 10 | // General error 11 | GENERAL, 12 | 13 | // Key pair related errors 14 | ADD_CARD_KEYPAIR_GENERATION, 15 | ERR_108_UNABLE_TO_DELETE_KEY_PAIR, 16 | ERR_207_UNABLE_TO_SIGN_CLAIMS_SET, 17 | 18 | // Server and network errors 19 | SERVER_ERROR, 20 | NO_INTERNET, 21 | SERVER_TIMEOUT, 22 | 23 | // Token related errors 24 | INVALID_TOKEN, 25 | NO_TOKENS_RETURNED; 26 | 27 | /** 28 | * Get a string representation of this alert key. 29 | * @return the name of the enum constant 30 | */ 31 | public String getKeyString() { 32 | return this.name(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /app/__tests__/screens/EnterBirthdateScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import EnterBirthdateScreen from '../../src/bcsc-theme/features/verify/EnterBirthdate/EnterBirthdateScreen' 7 | 8 | describe('EnterBirthdate', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | jest.setSystemTime(new Date('2025-12-03T00:00:00.000Z')) 16 | }) 17 | 18 | afterEach(() => { 19 | jest.useRealTimers() 20 | }) 21 | 22 | it('renders correctly', () => { 23 | const tree = render( 24 | 25 | 26 | 27 | ) 28 | 29 | expect(tree).toMatchSnapshot() 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /app/ios/GoogleService-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | API_KEY 6 | AIzaSyCL37I5zpWEauPopROBm6d64bGDiimAvZE 7 | GCM_SENDER_ID 8 | 1008044298583 9 | PLIST_VERSION 10 | 1 11 | BUNDLE_ID 12 | ca.bc.gov.BCWallet 13 | PROJECT_ID 14 | bc-wallet-mobile 15 | STORAGE_BUCKET 16 | bc-wallet-mobile.appspot.com 17 | IS_ADS_ENABLED 18 | 19 | IS_ANALYTICS_ENABLED 20 | 21 | IS_APPINVITE_ENABLED 22 | 23 | IS_GCM_ENABLED 24 | 25 | IS_SIGNIN_ENABLED 26 | 27 | GOOGLE_APP_ID 28 | 1:1008044298583:ios:76bfc02e8a3c04f844ae12 29 | 30 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/components/HeaderBackButton.tsx: -------------------------------------------------------------------------------- 1 | import { ButtonLocation, IconButton } from '@bifold/core' 2 | import { HeaderBackButtonProps } from '@react-navigation/elements' 3 | import { Platform } from 'react-native' 4 | 5 | /** 6 | * Shared Header Back Button component that navigates back on press. 7 | * 8 | * @returns {*} {JSX.Element} 9 | */ 10 | export const HeaderBackButton = (props: HeaderBackButtonProps) => { 11 | return ( 12 | props.onPress?.()} 18 | /> 19 | ) 20 | } 21 | 22 | /** 23 | * Creates a Header Back Button component. 24 | * 25 | * @returns {*} {JSX.Element} 26 | */ 27 | export const createHeaderBackButton = (props: HeaderBackButtonProps) => { 28 | return 29 | } 30 | -------------------------------------------------------------------------------- /app/__tests__/screens/AdditionalIdentificationRequiredScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import AdditionalIdentificationRequiredScreen from '../../src/bcsc-theme/features/verify/non-photo/AdditionalIdentificationRequiredScreen' 7 | 8 | describe('AdditionalIdentificationRequired', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 25 | 26 | ) 27 | 28 | expect(tree).toMatchSnapshot() 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/__tests__/screens/Developer.test.tsx: -------------------------------------------------------------------------------- 1 | import { AuthProvider } from '@bifold/core' 2 | import { render } from '@testing-library/react-native' 3 | import React from 'react' 4 | 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import Developer from '../../src/screens/Developer' 7 | 8 | describe('Developer Screen', () => { 9 | beforeEach(() => { 10 | // Silence console.error because it will print a warning about Switch 11 | // "Warning: dispatchCommand was called with a ref ...". 12 | jest.spyOn(console, 'error').mockImplementation(() => { 13 | return null 14 | }) 15 | jest.useFakeTimers() 16 | }) 17 | 18 | afterEach(() => { 19 | jest.clearAllMocks() 20 | jest.useRealTimers() 21 | }) 22 | 23 | test('screen renders correctly', () => { 24 | const tree = render( 25 | 26 | 27 | 28 | 29 | 30 | ) 31 | 32 | expect(tree).toMatchSnapshot() 33 | }) 34 | }) 35 | -------------------------------------------------------------------------------- /app/__tests__/screens/NotificationsScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import { NotificationsScreen } from '../../src/bcsc-theme/features/onboarding/NotificationsScreen' 7 | 8 | jest.mock('@assets/img/notifications.png', () => ({ uri: 'mock-notification-image' })) 9 | 10 | describe('Notifications', () => { 11 | let mockNavigation: any 12 | 13 | beforeEach(() => { 14 | mockNavigation = useNavigation() 15 | jest.clearAllMocks() 16 | jest.useFakeTimers() 17 | }) 18 | 19 | afterEach(() => { 20 | jest.useRealTimers() 21 | }) 22 | 23 | it('renders correctly', () => { 24 | const tree = render( 25 | 26 | 27 | 28 | ) 29 | 30 | expect(tree).toMatchSnapshot() 31 | }) 32 | }) 33 | -------------------------------------------------------------------------------- /app/__tests__/components/ProgressBar.test.tsx: -------------------------------------------------------------------------------- 1 | import { render, waitFor } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { BasicAppContext } from '../../__mocks__/helpers/app' 5 | import ProgressBar from '../../src/components/ProgressBar' 6 | 7 | describe('ProgressBar Component', () => { 8 | beforeAll(() => { 9 | jest.useFakeTimers() 10 | }) 11 | 12 | afterAll(() => { 13 | jest.useRealTimers() 14 | }) 15 | 16 | test('renders correctly', () => { 17 | const tree = render( 18 | 19 | 20 | 21 | ) 22 | 23 | waitFor(() => { 24 | expect(tree).toMatchSnapshot() 25 | }) 26 | }) 27 | 28 | test('renders correctly in dark mode', () => { 29 | const tree = render( 30 | 31 | 32 | 33 | ) 34 | 35 | waitFor(() => { 36 | expect(tree).toMatchSnapshot() 37 | }) 38 | }) 39 | }) 40 | -------------------------------------------------------------------------------- /app/__tests__/screens/EmailConfirmationScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import EmailConfirmationScreen from '../../src/bcsc-theme/features/verify/email/EmailConfirmationScreen' 7 | 8 | describe('EmailConfirmation', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const route = { params: { emailAddressId: 'test-email-id' } } 23 | const tree = render( 24 | 25 | 26 | 27 | ) 28 | 29 | expect(tree).toMatchSnapshot() 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/features/verify/live-call/components/CallProcessingView.tsx: -------------------------------------------------------------------------------- 1 | import { ThemedText, useTheme } from '@bifold/core' 2 | import { ActivityIndicator, StyleSheet } from 'react-native' 3 | import { SafeAreaView } from 'react-native-safe-area-context' 4 | 5 | type CallProcessingViewProps = { 6 | message?: string 7 | } 8 | 9 | const CallProcessingView = ({ message }: CallProcessingViewProps) => { 10 | const { Spacing, ColorPalette } = useTheme() 11 | const styles = StyleSheet.create({ 12 | pageContainer: { 13 | flex: 1, 14 | justifyContent: 'center', 15 | alignItems: 'center', 16 | backgroundColor: ColorPalette.brand.primaryBackground, 17 | }, 18 | }) 19 | 20 | return ( 21 | 22 | 23 | {message} 24 | 25 | 26 | 27 | ) 28 | } 29 | 30 | export default CallProcessingView 31 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/components/GenericCardImage.tsx: -------------------------------------------------------------------------------- 1 | import CardDetails from '@assets/img/card-details.svg' 2 | import { useTheme } from '@bifold/core' 3 | import React from 'react' 4 | import { View } from 'react-native' 5 | 6 | export const GENERIC_CARD_SIZE_SMALL = { height: 45, width: 72 } 7 | export const GENERIC_CARD_SIZE_MEDIUM = { height: 75, width: 120 } 8 | 9 | interface GenericCardImageProps { 10 | height?: number 11 | width?: number 12 | } 13 | 14 | const GenericCardImage = ({ height, width }: GenericCardImageProps) => { 15 | const { ColorPalette, Spacing } = useTheme() 16 | 17 | return ( 18 | 27 | 28 | 29 | ) 30 | } 31 | 32 | export default GenericCardImage 33 | -------------------------------------------------------------------------------- /packages/bcsc-core/android/src/main/java/com/bcsccore/bcsc-file-port/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | # Keep file port classes 24 | -keep class com.bcsccore.fileport.** { *; } 25 | -keepclassmembers class com.bcsccore.fileport.** { *; } 26 | -------------------------------------------------------------------------------- /app/__tests__/screens/IDPhotoInformationScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import IDPhotoInformationScreen from '../../src/bcsc-theme/features/verify/non-photo/IDPhotoInformationScreen' 7 | 8 | jest.mock('@assets/img/credential-scan.png', () => 1) 9 | 10 | describe('IDPhotoInformation', () => { 11 | let mockNavigation: any 12 | 13 | beforeEach(() => { 14 | mockNavigation = useNavigation() 15 | jest.clearAllMocks() 16 | jest.useFakeTimers() 17 | }) 18 | 19 | afterEach(() => { 20 | jest.useRealTimers() 21 | }) 22 | 23 | it('renders correctly', () => { 24 | const tree = render( 25 | 26 | 27 | 28 | ) 29 | 30 | expect(tree).toMatchSnapshot() 31 | }) 32 | }) 33 | -------------------------------------------------------------------------------- /app/__tests__/screens/VideoReviewScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import VideoReviewScreen from '../../src/bcsc-theme/features/verify/send-video/VideoReviewScreen' 7 | 8 | describe('VideoReview', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const route = { params: { videoPath: 'file://test.mp4', videoThumbnailPath: 'file://thumbnail.jpg' } } 23 | const tree = render( 24 | 25 | 26 | 27 | ) 28 | 29 | expect(tree).toMatchSnapshot() 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /app/__tests__/screens/__snapshots__/EvidenceCaptureScreen.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`EvidenceCapture renders correctly 1`] = ` 4 | 12 | 28 | 37 | 44 | BCSC.CameraDisclosure.NoCameraAvailable 45 | 46 | 47 | 48 | 49 | `; 50 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/features/account/NicknameAccountScreen.tsx: -------------------------------------------------------------------------------- 1 | import React, { useCallback } from 'react' 2 | 3 | import { BCSCScreens } from '@/bcsc-theme/types/navigators' 4 | import { BCDispatchAction, BCState } from '@/store' 5 | import { useStore } from '@bifold/core' 6 | import { CommonActions, useNavigation } from '@react-navigation/native' 7 | import NicknameForm from './components/NicknameForm' 8 | 9 | const NicknameAccountScreen: React.FC = () => { 10 | const navigation = useNavigation() 11 | const [, dispatch] = useStore() 12 | 13 | const handleSubmit = useCallback( 14 | (trimmedNickname: string) => { 15 | dispatch({ type: BCDispatchAction.ADD_NICKNAME, payload: [trimmedNickname] }) 16 | dispatch({ type: BCDispatchAction.SELECT_ACCOUNT, payload: [trimmedNickname] }) 17 | navigation.dispatch(CommonActions.reset({ index: 0, routes: [{ name: BCSCScreens.SetupSteps }] })) 18 | }, 19 | [dispatch, navigation] 20 | ) 21 | 22 | return 23 | } 24 | 25 | export default NicknameAccountScreen 26 | -------------------------------------------------------------------------------- /app/__tests__/screens/OnboardingOptInAnalyticsScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import { OnboardingOptInAnalyticsScreen } from '../../src/bcsc-theme/features/onboarding/OnboardingOptInAnalyticsScreen' 7 | 8 | jest.mock('@assets/img/notifications.png', () => ({ uri: 'mock-notification-image' })) 9 | 10 | describe('OnboardingOptInAnalytics', () => { 11 | let mockNavigation: any 12 | 13 | beforeEach(() => { 14 | mockNavigation = useNavigation() 15 | jest.clearAllMocks() 16 | jest.useFakeTimers() 17 | }) 18 | 19 | afterEach(() => { 20 | jest.useRealTimers() 21 | }) 22 | 23 | it('renders correctly', () => { 24 | const tree = render( 25 | 26 | 27 | 28 | ) 29 | 30 | expect(tree).toMatchSnapshot() 31 | }) 32 | }) 33 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/features/onboarding/OnboardingOptInAnalyticsScreen.tsx: -------------------------------------------------------------------------------- 1 | import { BCSCOnboardingStackParams, BCSCScreens } from '@/bcsc-theme/types/navigators' 2 | import { StackNavigationProp } from '@react-navigation/stack' 3 | import React from 'react' 4 | import { OnboardingOptInAnalyticsContent } from './components/OnboardingOptInAnalyticsContent' 5 | 6 | interface OnboardingOptInAnalyticsScreenProps { 7 | navigation: StackNavigationProp 8 | } 9 | 10 | /** 11 | * Opt-In Analytics screen component that allows users to choose whether to participate in analytics data collection. 12 | * @returns {*} {JSX.Element} The OnboardingOptInAnalyticsScreen component. 13 | */ 14 | export const OnboardingOptInAnalyticsScreen: React.FC = ({ 15 | navigation, 16 | }: OnboardingOptInAnalyticsScreenProps): JSX.Element => { 17 | const onPress = () => { 18 | navigation.navigate(BCSCScreens.OnboardingTermsOfUse) 19 | } 20 | 21 | return 22 | } 23 | -------------------------------------------------------------------------------- /app/__tests__/screens/PhotoInstructionsScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import PhotoInstructionsScreen from '../../src/bcsc-theme/features/verify/PhotoInstructionsScreen' 7 | 8 | describe('PhotoInstructions', () => { 9 | let mockNavigation: any 10 | 11 | beforeEach(() => { 12 | mockNavigation = useNavigation() 13 | jest.clearAllMocks() 14 | jest.useFakeTimers() 15 | }) 16 | 17 | afterEach(() => { 18 | jest.useRealTimers() 19 | }) 20 | 21 | it('renders correctly', () => { 22 | const tree = render( 23 | 24 | 28 | 29 | ) 30 | 31 | expect(tree).toMatchSnapshot() 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/api/hooks/useJwksApi.tsx: -------------------------------------------------------------------------------- 1 | import { useCallback, useMemo } from 'react' 2 | import BCSCApiClient from '../client' 3 | 4 | export interface JWK { 5 | kty: string 6 | e: string 7 | kid: string 8 | alg: string 9 | n: string 10 | } 11 | export type Keys = JWK[] 12 | 13 | export type JWKResponseData = { 14 | keys: Keys 15 | } 16 | 17 | const useJwksApi = (apiClient: BCSCApiClient) => { 18 | const getJwks = useCallback(async (): Promise => { 19 | const { 20 | data: { keys }, 21 | } = await apiClient.get(apiClient.endpoints.jwksURI, { 22 | skipBearerAuth: true, // this endpoint does not require an access token 23 | }) 24 | return keys 25 | }, [apiClient]) 26 | 27 | const getFirstJwk = useCallback(async (): Promise => { 28 | const keys = await getJwks() 29 | return keys.length > 0 ? keys[0] : null 30 | }, [getJwks]) 31 | 32 | return useMemo( 33 | () => ({ 34 | getJwks, 35 | getFirstJwk, 36 | }), 37 | [getJwks, getFirstJwk] 38 | ) 39 | } 40 | 41 | export default useJwksApi 42 | -------------------------------------------------------------------------------- /.github/workflows/actions/export-ios-archive/action.yml: -------------------------------------------------------------------------------- 1 | name: Export Signed iOS Archive 2 | description: Export a signed iOS Archive 3 | 4 | inputs: 5 | export_options: 6 | description: | 7 | The file containing the export options to use 8 | for signing the archive. 9 | required: true 10 | output_artifact_ref: 11 | description: | 12 | The reference ID / name of the uploaded GitHub artifact 13 | stored in GitHub by the upload action. 14 | required: true 15 | 16 | runs: 17 | using: composite 18 | steps: 19 | - name: Sign & Export 20 | shell: bash 21 | run: | 22 | xcodebuild \ 23 | -exportArchive \ 24 | -archivePath AriesBifold.xcarchive \ 25 | -exportPath export \ 26 | -exportOptionsPlist ./${{ inputs.export_options }} \ 27 | -verbose 28 | 29 | - name: Upload signed artifact 30 | uses: actions/upload-artifact@v4 31 | with: 32 | name: ${{ inputs.output_artifact_ref }} 33 | path: export/BCWallet.ipa 34 | if-no-files-found: error 35 | retention-days: 7 36 | -------------------------------------------------------------------------------- /app/__mocks__/@react-navigation/native.ts: -------------------------------------------------------------------------------- 1 | const navigate = jest.fn() 2 | const dispatch = jest.fn() 3 | const replace = jest.fn() 4 | const navigation = { 5 | __timestamp: process.hrtime(), 6 | navigate, 7 | replace, 8 | setOptions: jest.fn(), 9 | getParent: () => { 10 | return { 11 | navigate, 12 | dispatch, 13 | replace, 14 | } 15 | }, 16 | getState: jest.fn(() => ({ 17 | index: jest.fn(), 18 | })), 19 | goBack: jest.fn(), 20 | canGoBack: jest.fn(), 21 | pop: jest.fn(), 22 | reset: jest.fn(), 23 | isFocused: () => true, 24 | dispatch, 25 | } 26 | 27 | const useNavigation = () => { 28 | return navigation 29 | } 30 | 31 | const useIsFocused = () => { 32 | return true 33 | } 34 | 35 | const useRoute = jest.fn().mockReturnValue({ params: {} }) 36 | 37 | const CommonActions = { 38 | navigate: jest.fn(), 39 | reset: jest.fn(), 40 | goBack: jest.fn(), 41 | } 42 | 43 | const useFocusEffect = jest.fn() 44 | const createNavigatorFactory = jest.fn() 45 | 46 | export { CommonActions, createNavigatorFactory, useFocusEffect, useIsFocused, useNavigation, useRoute } 47 | -------------------------------------------------------------------------------- /packages/bcsc-core/BcscCore.podspec: -------------------------------------------------------------------------------- 1 | require "json" 2 | 3 | package = JSON.parse(File.read(File.join(__dir__, "package.json"))) 4 | 5 | Pod::Spec.new do |s| 6 | s.name = "BcscCore" 7 | s.version = package["version"] 8 | s.summary = package["description"] 9 | s.homepage = package["homepage"] 10 | s.license = package["license"] 11 | s.authors = package["author"] 12 | 13 | s.platforms = { :ios => "12.0" } # Or your min_ios_version_supported 14 | 15 | s.source = { :git => "https://github.com/bcgov/bc-wallet-mobile.git", :tag => "#{s.version}" } 16 | 17 | s.source_files = "ios/**/*.{h,m,mm,cpp,swift}" 18 | s.public_header_files = "ios/**/*.h" 19 | 20 | s.swift_version = '5.0' 21 | s.module_name = 'BcscCore' 22 | 23 | # Disable Swift optimizations to prevent cryptographic operations from being broken 24 | s.pod_target_xcconfig = { 25 | 'SWIFT_OPTIMIZATION_LEVEL' => '-Onone' 26 | } 27 | 28 | if respond_to?(:install_modules_dependencies, true) 29 | install_modules_dependencies(s) 30 | else 31 | s.dependency "React-Core" 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /packages/bcsc-core/eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import { fixupConfigRules } from '@eslint/compat'; 2 | import { FlatCompat } from '@eslint/eslintrc'; 3 | import js from '@eslint/js'; 4 | import { defineConfig } from 'eslint/config'; 5 | import path from 'node:path'; 6 | import { fileURLToPath } from 'node:url'; 7 | 8 | const __filename = fileURLToPath(import.meta.url); 9 | const __dirname = path.dirname(__filename); 10 | const compat = new FlatCompat({ 11 | baseDirectory: __dirname, 12 | recommendedConfig: js.configs.recommended, 13 | allConfig: js.configs.all, 14 | }); 15 | 16 | export default defineConfig([ 17 | { 18 | extends: fixupConfigRules(compat.extends('@react-native', 'prettier')), 19 | rules: { 20 | 'react/react-in-jsx-scope': 'off', 21 | 'prettier/prettier': [ 22 | 'error', 23 | { 24 | printWidth: 120, 25 | quoteProps: 'consistent', 26 | singleQuote: true, 27 | tabWidth: 2, 28 | trailingComma: 'es5', 29 | useTabs: false, 30 | }, 31 | ], 32 | }, 33 | ignores: ['node_modules/', 'lib/'], 34 | }, 35 | ]); 36 | -------------------------------------------------------------------------------- /ios-certificate.md: -------------------------------------------------------------------------------- 1 | # How to Re-Trust Your iOS Signing Certificate 2 | 3 | Occasionally, you may encounter a build issue on iOS that requires you to re-trust your signing certificate. Follow these steps to resolve the issue: 4 | 5 | 1. Open **Xcode**. 6 | 2. Go to the **Signing & Capabilities** tab of your project. 7 | 3. In the iOS section, locate the problematic certificate (it should be marked with an error). Note the certificate’s identifier or number. 8 | 4. Press `Cmd + Spacebar` to open Spotlight Search. 9 | 5. Search for and open **Keychain Access**. 10 | 6. In Keychain Access, select **My Certificates** under the **login** keychain. 11 | 7. Find the certificate matching the identifier or number from step 3. 12 | 8. Double-click the certificate to open its details. 13 | 9. Expand the **Trust** section. 14 | 10. Set **When using this certificate** to **Always Trust**. 15 | 11. Close the certificate details window. 16 | 12. Reopen **Xcode**. 17 | 13. Return to the **Signing & Capabilities** tab and click the **Repair Trust** button if available. 18 | 19 | Your signing certificate should now be trusted and the build issue resolved. 20 | -------------------------------------------------------------------------------- /app/__tests__/screens/InformationRequiredScreen.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import { BCSCLoadingProvider } from '../../src/bcsc-theme/contexts/BCSCLoadingContext' 7 | import InformationRequiredScreen from '../../src/bcsc-theme/features/verify/send-video/InformationRequiredScreen' 8 | 9 | describe('InformationRequired', () => { 10 | let mockNavigation: any 11 | 12 | beforeEach(() => { 13 | mockNavigation = useNavigation() 14 | jest.clearAllMocks() 15 | jest.useFakeTimers() 16 | }) 17 | 18 | afterEach(() => { 19 | jest.useRealTimers() 20 | }) 21 | 22 | it('renders correctly', () => { 23 | const tree = render( 24 | 25 | 26 | 27 | 28 | 29 | ) 30 | 31 | expect(tree).toMatchSnapshot() 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /app/__tests__/screens/__snapshots__/MainWebViewScreen.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`MainWebView renders correctly 1`] = ` 4 | 40 | `; 41 | -------------------------------------------------------------------------------- /app/__tests__/bcsc-theme/components/__snapshots__/PairingCodeTextInput.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`PairingCodeTextInput Component Rendering renders correctly 1`] = ` 4 | 12 | 43 | 44 | `; 45 | -------------------------------------------------------------------------------- /app/__tests__/screens/__snapshots__/VerifyWebViewScreen.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`VerifyWebView renders correctly 1`] = ` 4 | 40 | `; 41 | -------------------------------------------------------------------------------- /packages/bcsc-core/android/src/main/java/com/bcsccore/bcsc-file-port/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 35 5 | 6 | defaultConfig { 7 | minSdkVersion 23 8 | targetSdkVersion 35 9 | versionCode 1 10 | versionName "1.0" 11 | 12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 13 | } 14 | 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | 22 | compileOptions { 23 | sourceCompatibility JavaVersion.VERSION_1_8 24 | targetCompatibility JavaVersion.VERSION_1_8 25 | } 26 | } 27 | 28 | dependencies { 29 | implementation 'androidx.appcompat:appcompat:1.6.1' 30 | implementation 'androidx.annotation:annotation:1.7.0' 31 | 32 | testImplementation 'junit:junit:4.13.2' 33 | androidTestImplementation 'androidx.test.ext:junit:1.1.5' 34 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' 35 | } 36 | -------------------------------------------------------------------------------- /app/__tests__/screens/__snapshots__/OnboardingWebViewScreen.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`OnboardingWebView renders correctly 1`] = ` 4 | 40 | `; 41 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/hooks/useBCSCApiClient.tsx: -------------------------------------------------------------------------------- 1 | import { useContext } from 'react' 2 | import BCSCApiClient from '../api/client' 3 | import { BCSCApiClientContext } from '../contexts/BCSCApiClientContext' 4 | 5 | // Hook to be used for API calls, will throw if not configured properly 6 | export const useBCSCApiClient = (): BCSCApiClient => { 7 | const context = useContext(BCSCApiClientContext) 8 | 9 | if (!context) { 10 | throw new Error('useBCSCApiClient must be used within a BCSCApiClientProvider') 11 | } 12 | 13 | if (context.error) { 14 | throw new Error(`BCSC client error: ${context.error}`) 15 | } 16 | 17 | if (!context.client || !context.isClientReady) { 18 | throw new Error('BCSC client not ready. Make sure BCSCApiClientProvider is properly configured.') 19 | } 20 | 21 | return context.client 22 | } 23 | 24 | // Hook that doesn't throw, useful for checking readiness state 25 | export const useBCSCApiClientState = () => { 26 | const context = useContext(BCSCApiClientContext) 27 | 28 | if (!context) { 29 | throw new Error('useBCSCClientState must be used within a BCSCApiClientProvider') 30 | } 31 | 32 | return context 33 | } 34 | -------------------------------------------------------------------------------- /packages/bcsc-core/android/src/main/java/com/bcsccore/bcsc-keypair-port/build.gradle.template: -------------------------------------------------------------------------------- 1 | // Build.gradle template for using the BC Services Card KeyPair functionality 2 | // Add these dependencies to your app's build.gradle file 3 | 4 | android { 5 | compileSdkVersion 34 6 | 7 | defaultConfig { 8 | minSdkVersion 23 // Required for Android KeyStore features 9 | targetSdkVersion 34 10 | } 11 | 12 | compileOptions { 13 | sourceCompatibility JavaVersion.VERSION_1_8 14 | targetCompatibility JavaVersion.VERSION_1_8 15 | } 16 | } 17 | 18 | dependencies { 19 | // Required: Nimbus JOSE library for JWT operations 20 | implementation 'com.nimbusds:nimbus-jose-jwt:9.37.3' 21 | 22 | // Required: Android annotations 23 | implementation 'androidx.annotation:annotation:1.7.0' 24 | 25 | // Required: Gson for JSON serialization (used by SimpleKeyPairInfoSource) 26 | implementation 'com.google.code.gson:gson:2.10.1' 27 | 28 | // Optional: If you want to use more advanced storage instead of SharedPreferences 29 | // implementation 'androidx.security:security-crypto:1.1.0-alpha06' 30 | } 31 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/features/services/components/ServiceButton.tsx: -------------------------------------------------------------------------------- 1 | import { ThemedText, useTheme } from '@bifold/core' 2 | import React from 'react' 3 | import { StyleSheet, TouchableOpacity } from 'react-native' 4 | 5 | interface ServiceButtonProps { 6 | title: string 7 | description?: string 8 | onPress: () => void 9 | } 10 | 11 | const ServiceButton: React.FC = ({ title, description, onPress }) => { 12 | const { ColorPalette, Spacing } = useTheme() 13 | 14 | const styles = StyleSheet.create({ 15 | container: { 16 | padding: Spacing.md, 17 | backgroundColor: ColorPalette.brand.secondaryBackground, 18 | }, 19 | title: { 20 | marginBottom: Spacing.sm, 21 | color: ColorPalette.brand.primary, 22 | }, 23 | }) 24 | 25 | return ( 26 | 27 | 28 | {title} 29 | 30 | {description ? {description} : null} 31 | 32 | ) 33 | } 34 | 35 | export default ServiceButton 36 | -------------------------------------------------------------------------------- /app/__tests__/screens/PersonCredential.test.tsx: -------------------------------------------------------------------------------- 1 | import { render } from '@testing-library/react-native' 2 | import React from 'react' 3 | 4 | import { useNavigation } from '../../__mocks__/custom/@react-navigation/core' 5 | import { BasicAppContext } from '../../__mocks__/helpers/app' 6 | import PersonCredential from '../../src/bcwallet-theme/features/person-flow/screens/PersonCredential' 7 | 8 | describe('Person Credential Screen', () => { 9 | beforeEach(() => { 10 | // Silence console.error because it will print a warning about Switch 11 | // "Warning: dispatchCommand was called with a ref ...". 12 | jest.spyOn(console, 'error').mockImplementation(() => { 13 | return null 14 | }) 15 | jest.useFakeTimers() 16 | }) 17 | 18 | afterEach(() => { 19 | jest.clearAllMocks() 20 | jest.useRealTimers() 21 | }) 22 | 23 | test('screen renders correctly', () => { 24 | const navigation = useNavigation() 25 | const tree = render( 26 | 27 | 28 | 29 | ) 30 | 31 | expect(tree).toMatchSnapshot() 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /app/ios/AriesBifold/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | struct rlimit rlim; 8 | unsigned long long NEW_SOFT_LIMIT = 1024; 9 | 10 | //Fetch existing file limits, adjust file limits if possible 11 | if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 12 | NSLog(@"Current soft RLimit: %llu", rlim.rlim_cur); 13 | NSLog(@"Current hard RLimit: %llu", rlim.rlim_max); 14 | 15 | // Adjust only if the limit is less than NEW_SOFT_LIMIT 16 | if(rlim.rlim_cur < NEW_SOFT_LIMIT){ 17 | rlim.rlim_cur = NEW_SOFT_LIMIT; 18 | } 19 | 20 | if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) { 21 | NSLog(@"Can't set RLimits"); 22 | } 23 | } else { 24 | NSLog(@"Can't fetch RLimits"); 25 | } 26 | 27 | // Re-fetch file limits 28 | if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { 29 | NSLog(@"New soft RLimit: %llu", rlim.rlim_cur); 30 | NSLog(@"New hard RLimit: %llu", rlim.rlim_max); 31 | } else { 32 | NSLog(@"Can't fetch RLimits"); 33 | } 34 | 35 | @autoreleasepool { 36 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/android/app/google-services.json: -------------------------------------------------------------------------------- 1 | { 2 | "project_info": { 3 | "project_number": "1008044298583", 4 | "project_id": "bc-wallet-mobile", 5 | "storage_bucket": "bc-wallet-mobile.appspot.com" 6 | }, 7 | "client": [ 8 | { 9 | "client_info": { 10 | "mobilesdk_app_id": "1:1008044298583:android:56bf7c25b882152a44ae12", 11 | "android_client_info": { 12 | "package_name": "ca.bc.gov.BCWallet" 13 | } 14 | }, 15 | "oauth_client": [ 16 | { 17 | "client_id": "1008044298583-12lpkisi403oa5bc5hs0800o48cl4nhj.apps.googleusercontent.com", 18 | "client_type": 3 19 | } 20 | ], 21 | "api_key": [ 22 | { 23 | "current_key": "AIzaSyB9TMILh7AQmEGCdwvvmDeN-WG4G345p9I" 24 | } 25 | ], 26 | "services": { 27 | "appinvite_service": { 28 | "other_platform_oauth_client": [ 29 | { 30 | "client_id": "1008044298583-12lpkisi403oa5bc5hs0800o48cl4nhj.apps.googleusercontent.com", 31 | "client_type": 3 32 | } 33 | ] 34 | } 35 | } 36 | } 37 | ], 38 | "configuration_version": "1" 39 | } -------------------------------------------------------------------------------- /app/__tests__/bcsc-theme/components/LoadingScreenContent.test.tsx: -------------------------------------------------------------------------------- 1 | import { LoadingScreenContent } from '@/bcsc-theme/features/splash-loading/LoadingScreenContent' 2 | import { render } from '@testing-library/react-native' 3 | 4 | describe('LoadingScreenContent Component', () => { 5 | it('renders message', () => { 6 | const tree = render() 7 | 8 | expect(tree.getByText('TEST_LOADINGSCREENCONTENT')).toBeTruthy() 9 | }) 10 | 11 | it('runs onLoaded callback when loading is false', () => { 12 | const onLoadedMock = jest.fn() 13 | 14 | render() 15 | 16 | expect(onLoadedMock).toHaveBeenCalledTimes(1) 17 | }) 18 | 19 | it('does not run onLoaded callback when loading is true', () => { 20 | const onLoadedMock = jest.fn() 21 | 22 | const { rerender } = render() 23 | 24 | expect(onLoadedMock).not.toHaveBeenCalled() 25 | 26 | rerender() 27 | 28 | expect(onLoadedMock).toHaveBeenCalledTimes(1) 29 | }) 30 | }) 31 | -------------------------------------------------------------------------------- /app/src/bcsc-theme/features/home/components/HomeHeader.tsx: -------------------------------------------------------------------------------- 1 | import GenericCardImage from '@/bcsc-theme/components/GenericCardImage' 2 | import { ThemedText, useTheme } from '@bifold/core' 3 | import React from 'react' 4 | import { StyleSheet, View } from 'react-native' 5 | 6 | interface HomeHeaderProps { 7 | name: string 8 | fontSize?: number 9 | cardSize?: { 10 | height: number 11 | width: number 12 | } 13 | } 14 | 15 | const HomeHeader: React.FC = ({ name, cardSize, fontSize }) => { 16 | const { Spacing } = useTheme() 17 | 18 | const styles = StyleSheet.create({ 19 | container: { 20 | padding: Spacing.md, 21 | }, 22 | idContainer: { 23 | justifyContent: 'center', 24 | alignItems: 'center', 25 | }, 26 | }) 27 | 28 | return ( 29 | 30 | 31 | 32 | 33 | {name} 34 | 35 | 36 | 37 | ) 38 | } 39 | 40 | export default HomeHeader 41 | -------------------------------------------------------------------------------- /app/src/screens/WebDisplay.tsx: -------------------------------------------------------------------------------- 1 | import { SafeAreaModal } from '@bifold/core' 2 | import React from 'react' 3 | import { StyleSheet } from 'react-native' 4 | import { WebView, WebViewNavigation } from 'react-native-webview' 5 | 6 | interface WebDisplayProps { 7 | destinationUrl: string 8 | visible: boolean 9 | onClose: () => void 10 | exitUrl: string 11 | } 12 | 13 | const WebDisplay = ({ destinationUrl, exitUrl, visible, onClose }: WebDisplayProps) => { 14 | const styles = StyleSheet.create({ 15 | container: { 16 | flex: 1, 17 | justifyContent: 'center', 18 | alignItems: 'center', 19 | marginTop: 32, 20 | }, 21 | }) 22 | 23 | return ( 24 | 25 | { 31 | if (exitUrl && nav.url.includes(exitUrl)) { 32 | onClose() 33 | } 34 | }} 35 | /> 36 | 37 | ) 38 | } 39 | 40 | export default WebDisplay 41 | -------------------------------------------------------------------------------- /app/__mocks__/custom/react-native-localize.ts: -------------------------------------------------------------------------------- 1 | const getLocales = () => [ 2 | { countryCode: 'US', languageTag: 'en-US', languageCode: 'en', isRTL: false }, 3 | { countryCode: 'NL', languageTag: 'nl-NL', languageCode: 'nl', isRTL: false }, 4 | { countryCode: 'FR', languageTag: 'fr-FR', languageCode: 'fr', isRTL: false }, 5 | ] 6 | 7 | const getNumberFormatSettings = () => ({ 8 | decimalSeparator: '.', 9 | groupingSeparator: ',', 10 | }) 11 | 12 | const getCalendar = () => 'gregorian' // or "japanese", "buddhist" 13 | const getCountry = () => 'US' // the country code you want 14 | const getCurrencies = () => ['USD'] // can be empty array 15 | const getTemperatureUnit = () => 'celsius' // or "fahrenheit" 16 | const getTimeZone = () => 'America/Los_Angeles' // the timezone you want 17 | const uses24HourClock = () => true 18 | const usesMetricSystem = () => true 19 | 20 | const addEventListener = jest.fn() 21 | const removeEventListener = jest.fn() 22 | 23 | export { 24 | addEventListener, 25 | getCalendar, 26 | getCountry, 27 | getCurrencies, 28 | getLocales, 29 | getNumberFormatSettings, 30 | getTemperatureUnit, 31 | getTimeZone, 32 | removeEventListener, 33 | uses24HourClock, 34 | usesMetricSystem, 35 | } 36 | -------------------------------------------------------------------------------- /app/src/components/LoadingIcon.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useRef } from 'react' 2 | import { Animated } from 'react-native' 3 | import Icon from 'react-native-vector-icons/MaterialIcons' 4 | 5 | interface LoadingIconProps { 6 | size: number 7 | color: string 8 | active: boolean 9 | } 10 | 11 | const timing: Animated.TimingAnimationConfig = { 12 | toValue: 1, 13 | duration: 2000, 14 | useNativeDriver: true, 15 | } 16 | 17 | export default function LoadingIcon({ size, color, active }: Readonly) { 18 | const rotationAnim = useRef(new Animated.Value(0)) 19 | const rotation = rotationAnim.current.interpolate({ 20 | inputRange: [0, 1], 21 | outputRange: ['0deg', '360deg'], 22 | }) 23 | 24 | const animation = Animated.loop(Animated.timing(rotationAnim.current, timing)) 25 | 26 | useEffect(() => { 27 | animation.reset() 28 | if (active) { 29 | animation.start() 30 | } else { 31 | animation.stop() 32 | } 33 | }, [animation, active]) 34 | 35 | return ( 36 | <> 37 | 38 | 39 | 40 | 41 | ) 42 | } 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Merge artifacts 6 | *.orig 7 | build/ 8 | xbuild/ 9 | 10 | # Secrets 11 | *.mobileprovision 12 | *.p12 13 | *.p8 14 | pc-api*.json 15 | api*.json 16 | *secret* 17 | *secrets* 18 | .env 19 | .idea/ 20 | 21 | # Other 22 | node_modules 23 | .gradle 24 | lib 25 | local.properties 26 | .jest 27 | .npmrc 28 | 29 | # yarn 30 | .yarn/* 31 | .yarn/cache 32 | !.yarn/patches 33 | !.yarn/plugins 34 | !.yarn/releases 35 | !.yarn/sdks 36 | !.yarn/versions 37 | app/.yarn/* 38 | app/.yarn/cache 39 | !app/.yarn/patches 40 | !app/.yarn/plugins 41 | !app/.yarn/releases 42 | !app/.yarn/sdks 43 | !app/.yarn/versions 44 | yarn-debug.log* 45 | yarn-error.log* 46 | .yarn-integrity 47 | 48 | # aries-bifold should be cloned separately 49 | aries-bifold/ 50 | *.code-workspace 51 | 52 | # 3rd-party 53 | app/ios/Pods/* 54 | !app/ios/Pods/Frameworks 55 | 56 | # This patch must be dynamically generated by something 57 | # so its excluded. 58 | app/patches/react-native-gifted-chat*.patch 59 | 60 | # xcode 61 | xcuserdata/ 62 | .xcode.env.local 63 | 64 | # gem 65 | app/vendor/bundle/** 66 | 67 | # child packages 68 | bifold/ 69 | aries-oca-bundles/ 70 | credo-ts/ 71 | app/vendor/ 72 | 73 | .metro-cache/ 74 | 75 | coverage/ 76 | -------------------------------------------------------------------------------- /app/src/hooks/useEventListener.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from 'react' 2 | 3 | type RemoveListenerCallback = () => void 4 | 5 | /** 6 | * Hook to manage attaching and detaching to event listeners. 7 | * 8 | * Note: The eventListener function should return a function that removes the event listener when called. 9 | * This is to prevent memory leaks by ensuring that all event listners are properly cleaned up on component unmount. 10 | * 11 | * @param {() => RemoveListenerCallback} eventListener - Function that attaches the event listener and returns a function to remove it. 12 | * @param {boolean} [canAttach=true] - Flag to determine if the event listener should be attached. 13 | * @returns {*} {void} 14 | */ 15 | export const useEventListener = (eventListener: () => RemoveListenerCallback, canAttach = true) => { 16 | // This prevents re-creating the event listener on every render 17 | const eventListenerRef = useRef(eventListener) 18 | 19 | useEffect(() => { 20 | if (!canAttach) { 21 | return 22 | } 23 | 24 | const removeListener = eventListenerRef.current() 25 | 26 | // Cleanup function to remove the event listener on unmount 27 | return removeListener 28 | }, [canAttach]) // only re-run if canAttach changes 29 | } 30 | -------------------------------------------------------------------------------- /devops/charts/loki-logstack/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: logstack 3 | description: A Helm chart for Kubernetes 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: application 14 | 15 | # This is the chart version. This version number should be incremented each time you make changes 16 | # to the chart and its templates, including the app version. 17 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 18 | version: 0.0.1 19 | 20 | # This is the version number of the application being deployed. This version number should be 21 | # incremented each time you make changes to the application. Versions are not expected to 22 | # follow Semantic Versioning. They should reflect the version the application is using. 23 | # It is recommended to use it with quotes. 24 | appVersion: "0.0.1" 25 | -------------------------------------------------------------------------------- /.github/workflows/actions/send-rocketchat-notification/action.yml: -------------------------------------------------------------------------------- 1 | # Makes use of https://github.com/RocketChat/Rocket.Chat.GitHub.Action.Notification 2 | name: Rocketchat Notification 3 | description: Send a rocketchat notification 4 | author: "bryce.j.mcmath@gmail.com" 5 | 6 | inputs: 7 | job_title: 8 | description: The title of the notification 9 | required: true 10 | job_status: 11 | description: The status of the job 12 | required: true 13 | webhook_url: 14 | description: | 15 | The RocketChat Webhook URL as copied from Rocket.Chat. 16 | required: true 17 | github_token: 18 | description: | 19 | The GitHub access token for the action so it can fetch 20 | information from the GitHub API. 21 | required: false 22 | 23 | runs: 24 | using: composite 25 | steps: 26 | - name: Notification 27 | uses: RocketChat/Rocket.Chat.GitHub.Action.Notification@master 28 | with: 29 | type: ${{ inputs.job_status }} 30 | job_name: ${{ inputs.job_title }} 31 | mention: "jason.leach @cvarjao @wade.king @bryce.mcmath" 32 | mention_if: always 33 | channel: "#ditp-digital-wallet-core-team" 34 | commit: true 35 | url: ${{ inputs.webhook_url }} 36 | token: ${{ inputs.github_token }} 37 | -------------------------------------------------------------------------------- /app/__tests__/components/NavigationContainerContext.test.tsx: -------------------------------------------------------------------------------- 1 | import { NavigationContainerContext, NavigationContainerProvider } from '@/contexts/NavigationContainerContext' 2 | import { renderHook } from '@testing-library/react-native' 3 | import { useContext } from 'react' 4 | 5 | jest.mock('@react-navigation/native', () => ({ 6 | NavigationContainer: ({ children }: any) => <>{children}, 7 | createNavigationContainerRef: jest.fn(() => ({ 8 | current: { 9 | getCurrentRoute: jest.fn(() => ({ name: undefined })), 10 | }, 11 | })), 12 | })) 13 | 14 | jest.mock('@bifold/core', () => ({ 15 | useTheme: jest.fn(() => ({ 16 | NavigationTheme: {}, 17 | })), 18 | })) 19 | 20 | jest.mock('@/utils/analytics/analytics-singleton', () => ({ 21 | Analytics: { 22 | trackScreenEvent: jest.fn(), 23 | }, 24 | })) 25 | 26 | describe('NavigationContainerContext', () => { 27 | it('should have isNavigationReady as false by default', () => { 28 | const wrapper = ({ children }: { children: React.ReactNode }) => { 29 | return {children} 30 | } 31 | 32 | const { result } = renderHook(() => useContext(NavigationContainerContext), { wrapper }) 33 | 34 | expect(result.current?.isNavigationReady).toBe(false) 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /app/src/services/version.ts: -------------------------------------------------------------------------------- 1 | import { BifoldLogger, IVersionCheckService, VersionInfo } from '@bifold/core' 2 | import { checkVersion } from 'react-native-check-version' 3 | 4 | export class VersionCheckService implements IVersionCheckService { 5 | private _cachedVersionInfo: VersionInfo | undefined 6 | 7 | constructor(private readonly log: BifoldLogger) { 8 | // Logger is now injected 9 | } 10 | 11 | get lastChecked(): Date | undefined { 12 | return this._cachedVersionInfo?.lastChecked 13 | } 14 | 15 | async checkForUpdate(forceCheck: boolean = false): Promise { 16 | if (forceCheck || !this._cachedVersionInfo) { 17 | try { 18 | const version = await checkVersion() 19 | const now = new Date() 20 | 21 | const versionInfo: VersionInfo = { 22 | version: version.version, 23 | needsUpdate: version.needsUpdate, 24 | lastChecked: now, 25 | } 26 | 27 | this._cachedVersionInfo = versionInfo 28 | 29 | this.log.info('Checked for updates:', { ...version }) 30 | return versionInfo 31 | } catch (error) { 32 | this.log.error('Failed to check for updates:', error as Error) 33 | return undefined 34 | } 35 | } 36 | 37 | return this._cachedVersionInfo 38 | } 39 | } 40 | --------------------------------------------------------------------------------