Feat: Deprecate amplitude, remove unused packages (#126)

This commit is contained in:
Justin Hernandez
2025-02-17 09:50:52 -06:00
committed by GitHub
parent ee17b5505c
commit 99d81d5c92
22 changed files with 96 additions and 1450 deletions

View File

@@ -1 +0,0 @@
AMPLITUDE_KEY=amplitude_api_key

View File

@@ -2,13 +2,10 @@ import React, { useEffect } from 'react';
import 'react-native-get-random-values';
import Orientation from 'react-native-orientation-locker';
import { createClient } from '@segment/analytics-react-native';
import { Buffer } from 'buffer';
import { YStack } from 'tamagui';
// Adjust the import path as needed
import AppNavigation from './src/Navigation';
import { createSegmentClient } from './src/Segment';
import { AppProvider } from './src/stores/appProvider';
import { AuthProvider } from './src/stores/authProvider';
import { PassportProvider } from './src/stores/passportDataProvider';
@@ -16,13 +13,8 @@ import { ProofProvider } from './src/stores/proofProvider';
global.Buffer = Buffer;
// Export the client variable (will be initialized later)
export let segmentClient: ReturnType<typeof createClient> | null = null;
function App(): React.JSX.Element {
useEffect(() => {
// init
segmentClient = createSegmentClient();
Orientation.lockToPortrait();
// cleanup
return () => {

View File

@@ -150,7 +150,6 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
implementation("net.java.dev.jna:jna:5.13.0@aar")
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android'
implementation project(':react-native-fs')
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'com.google.android.gms:play-services-mlkit-text-recognition-common:19.1.0'

View File

@@ -7,6 +7,4 @@ includeBuild('../node_modules/@react-native/gradle-plugin')
include ':react-native-passport-reader'
project(':react-native-passport-reader').projectDir = new File(rootProject.projectDir, './react-native-passport-reader/android')
include ':passportreader'
project(':passportreader').projectDir = new File(rootProject.projectDir, './android-passport-reader/app')
include ':react-native-fs'
project(':react-native-fs').projectDir = new File(settingsDir, '../node_modules/react-native-fs/android')
project(':passportreader').projectDir = new File(rootProject.projectDir, './android-passport-reader/app')

View File

@@ -1,30 +0,0 @@
/**
* @format
*/
import React from 'react';
import { AppRegistry, LogBox } from 'react-native';
import { config } from '@tamagui/config/v2-native';
import { ToastProvider } from '@tamagui/toast';
import { TamaguiProvider, createTamagui } from 'tamagui';
import App from './App';
import { name as appName } from './app.json';
const tamaguiConfig = createTamagui(config);
LogBox.ignoreLogs([
/bad setState/,
'Warning, duplicate ID for input',
/Warning, duplicate ID for input/,
]);
const Root = () => (
<TamaguiProvider config={tamaguiConfig}>
<ToastProvider swipeDirection="up">
<App />
</ToastProvider>
</TamaguiProvider>
);
AppRegistry.registerComponent(appName, () => Root);

View File

@@ -26,7 +26,6 @@ target 'Self' do
use_frameworks!
pod 'NFCPassportReader', git: 'https://github.com/zk-passport/NFCPassportReader', commit: '8e72f0a2d3ca3bede00304bd22ed10829535dd53'
pod 'QKMRZScanner'
pod 'RNFS', :path => '../node_modules/react-native-fs'
pod 'lottie-ios'
pod 'SwiftQRScanner', :git => 'https://github.com/vinodiOS/SwiftQRScanner'
pod 'RNReactNativeHapticFeedback', :path => '../node_modules/react-native-haptic-feedback', :modular_headers => true

View File

@@ -1,6 +1,4 @@
PODS:
- amplitude-react-native (1.4.11):
- React-Core
- AppAuth (1.7.6):
- AppAuth/Core (= 1.7.6)
- AppAuth/ExternalUserAgent (= 1.7.6)
@@ -1278,22 +1276,14 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- react-native-date-picker (4.3.7):
- React-Core
- react-native-get-random-values (1.11.0):
- React-Core
- react-native-netinfo (11.4.1):
- React-Core
- react-native-nfc-manager (3.16.1):
- React-Core
- react-native-orientation-locker (1.7.0):
- React-Core
- react-native-randombytes (3.6.1):
- React-Core
- react-native-safe-area-context (5.2.0):
- React-Core
- react-native-tracking-transparency (0.1.2):
- React
- React-nativeconfig (0.75.4)
- React-NativeModulesApple (0.75.4):
- glog
@@ -1543,8 +1533,6 @@ PODS:
- React-Core
- RNDeviceInfo (14.0.4):
- React-Core
- RNFS (2.20.0):
- React-Core
- RNGestureHandler (2.22.1):
- DoubleConversion
- glog
@@ -1618,26 +1606,17 @@ PODS:
- Yoga
- RNSVG (15.11.1):
- React-Core
- RNZipArchive (6.1.2):
- React-Core
- RNZipArchive/Core (= 6.1.2)
- SSZipArchive (~> 2.2)
- RNZipArchive/Core (6.1.2):
- React-Core
- SSZipArchive (~> 2.2)
- segment-analytics-react-native (2.20.3):
- React-Core
- sovran-react-native
- SocketRocket (0.7.0)
- sovran-react-native (1.1.3):
- React-Core
- SSZipArchive (2.4.3)
- SwiftQRScanner (1.1.6)
- SwiftyTesseract (3.1.3)
- Yoga (0.0.0)
DEPENDENCIES:
- "amplitude-react-native (from `../node_modules/@amplitude/analytics-react-native`)"
- boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`)
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
@@ -1680,14 +1659,10 @@ DEPENDENCIES:
- React-microtasksnativemodule (from `../node_modules/react-native/ReactCommon/react/nativemodule/microtasks`)
- react-native-biometrics (from `../node_modules/react-native-biometrics`)
- react-native-cloud-storage (from `../node_modules/react-native-cloud-storage`)
- react-native-date-picker (from `../node_modules/react-native-date-picker`)
- react-native-get-random-values (from `../node_modules/react-native-get-random-values`)
- "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)"
- react-native-nfc-manager (from `../node_modules/react-native-nfc-manager`)
- react-native-orientation-locker (from `../node_modules/react-native-orientation-locker`)
- react-native-randombytes (from `../node_modules/react-native-randombytes`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- react-native-tracking-transparency (from `../node_modules/react-native-tracking-transparency`)
- React-nativeconfig (from `../node_modules/react-native/ReactCommon`)
- React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`)
- React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
@@ -1716,7 +1691,6 @@ DEPENDENCIES:
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
- RNFS (from `../node_modules/react-native-fs`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- "RNGoogleSignin (from `../node_modules/@react-native-google-signin/google-signin`)"
- RNKeychain (from `../node_modules/react-native-keychain`)
@@ -1724,7 +1698,6 @@ DEPENDENCIES:
- RNReactNativeHapticFeedback (from `../node_modules/react-native-haptic-feedback`)
- RNScreens (from `../node_modules/react-native-screens`)
- RNSVG (from `../node_modules/react-native-svg`)
- RNZipArchive (from `../node_modules/react-native-zip-archive`)
- "segment-analytics-react-native (from `../node_modules/@segment/analytics-react-native`)"
- "sovran-react-native (from `../node_modules/@segment/sovran-react-native`)"
- SwiftQRScanner (from `https://github.com/vinodiOS/SwiftQRScanner`)
@@ -1741,12 +1714,9 @@ SPEC REPOS:
- QKMRZParser
- QKMRZScanner
- SocketRocket
- SSZipArchive
- SwiftyTesseract
EXTERNAL SOURCES:
amplitude-react-native:
:path: "../node_modules/@amplitude/analytics-react-native"
boost:
:podspec: "../node_modules/react-native/third-party-podspecs/boost.podspec"
DoubleConversion:
@@ -1824,22 +1794,14 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-biometrics"
react-native-cloud-storage:
:path: "../node_modules/react-native-cloud-storage"
react-native-date-picker:
:path: "../node_modules/react-native-date-picker"
react-native-get-random-values:
:path: "../node_modules/react-native-get-random-values"
react-native-netinfo:
:path: "../node_modules/@react-native-community/netinfo"
react-native-nfc-manager:
:path: "../node_modules/react-native-nfc-manager"
react-native-orientation-locker:
:path: "../node_modules/react-native-orientation-locker"
react-native-randombytes:
:path: "../node_modules/react-native-randombytes"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
react-native-tracking-transparency:
:path: "../node_modules/react-native-tracking-transparency"
React-nativeconfig:
:path: "../node_modules/react-native/ReactCommon"
React-NativeModulesApple:
@@ -1896,8 +1858,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-clipboard/clipboard"
RNDeviceInfo:
:path: "../node_modules/react-native-device-info"
RNFS:
:path: "../node_modules/react-native-fs"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
RNGoogleSignin:
@@ -1912,8 +1872,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native-screens"
RNSVG:
:path: "../node_modules/react-native-svg"
RNZipArchive:
:path: "../node_modules/react-native-zip-archive"
segment-analytics-react-native:
:path: "../node_modules/@segment/analytics-react-native"
sovran-react-native:
@@ -1932,7 +1890,6 @@ CHECKOUT OPTIONS:
:git: https://github.com/vinodiOS/SwiftQRScanner
SPEC CHECKSUMS:
amplitude-react-native: 9d57e1bcc4175039e36283390aa3daeaea9441a5
AppAuth: d4f13a8fe0baf391b2108511793e4b479691fb73
boost: 4cb898d0bf20404aab1850c656dcea009429d6c1
DoubleConversion: 76ab83afb40bddeeee456813d9c04f67f78771b5
@@ -1979,14 +1936,10 @@ SPEC CHECKSUMS:
React-microtasksnativemodule: 744f7e26200ea3976fef8453101cefcc08756008
react-native-biometrics: 352e5a794bfffc46a0c86725ea7dc62deb085bdc
react-native-cloud-storage: 4c68bc6025c3624164461e15231efb28576f78a8
react-native-date-picker: 5637f417bb0c1981bc9d483324d5eb5929a1651c
react-native-get-random-values: 21325b2244dfa6b58878f51f9aa42821e7ba3d06
react-native-netinfo: f0a9899081c185db1de5bb2fdc1c88c202a059ac
react-native-nfc-manager: 5213321cf6c18d879c8092c0bf56806b771ec5ac
react-native-orientation-locker: 5819fd23ca89cbac0d736fb4314745f62716d517
react-native-randombytes: 421f1c7d48c0af8dbcd471b0324393ebf8fe7846
react-native-safe-area-context: 849d7df29ecb2a7155c769c0b76849ba952c2aa3
react-native-tracking-transparency: 25ff1ff866e338c137c818bdec20526bb05ffcc1
React-nativeconfig: 31072ab0146e643594f6959c7f970a04b6c9ddd0
React-NativeModulesApple: 5df767d9a2197ac25f4d8dd2d4ae1af3624022e2
React-perflogger: 59e1a3182dca2cee7b9f1f7aab204018d46d1914
@@ -2015,7 +1968,6 @@ SPEC CHECKSUMS:
RNCAsyncStorage: 03861ec2e1e46b20e51963c62c51dc288beb7c43
RNCClipboard: 60fed4b71560d7bfe40e9d35dea9762b024da86d
RNDeviceInfo: feea80a690d2bde1fe51461cf548039258bd03f2
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNGestureHandler: e705387b01bba53f4643bdff381ee08c7b9679a1
RNGoogleSignin: 9e68b9bcc3888219357924e32ee563624745647d
RNKeychain: bfe3d12bf4620fe488771c414530bf16e88f3678
@@ -2023,15 +1975,13 @@ SPEC CHECKSUMS:
RNReactNativeHapticFeedback: cba92e59f56506f6058d261dc85986012b2c5032
RNScreens: 7cdbd2d97472f2838cee0d53171a89e7e0c30991
RNSVG: 669ed128ab9005090c612a0d627dbecb6ab5c76f
RNZipArchive: 6d736ee4e286dbbd9d81206b7a4da355596ca04a
segment-analytics-react-native: d57ed4971cbb995706babf29215ebdbf242ecdab
SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
sovran-react-native: eec37f82e4429f0e3661f46aaf4fcd85d1b54f60
SSZipArchive: fe6a26b2a54d5a0890f2567b5cc6de5caa600aef
SwiftQRScanner: e85a25f9b843e9231dab89a96e441472fe54a724
SwiftyTesseract: 1f3d96668ae92dc2208d9842c8a59bea9fad2cbb
Yoga: b05994d1933f507b0a28ceaa4fdb968dc18da178
PODFILE CHECKSUM: 25704f1dbb82370ab76e89f27dbbb767901f31f4
PODFILE CHECKSUM: bb88cf7d6b3add1093ce81781efdb84e78ac6c04
COCOAPODS: 1.16.2

View File

@@ -3,11 +3,10 @@
"version": "2.2.2",
"private": true,
"scripts": {
"analyze-android": "react-native-bundle-visualizer --platform android --dev",
"analyze-ios": "react-native-bundle-visualizer --platform ios --dev",
"android": "react-native run-android",
"android:build-debug": "cd ./android && yarn android:build-debug-bundle && ./gradlew clean assembleDebug && cd ..",
"android:build-debug-bundle": "yarn react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/",
"android-analyze": "yarn reinstall && react-native-bundle-visualizer --platform android --dev",
"clean": "watchman watch-del-all && rm -rf node_modules ios/Pods ios/build android/app/build android/build .yarn/cache ios/.xcode.env.local",
"clean:xcode-env-local": "rm -f ios/.xcode.env.local",
"fmt": "prettier --check .",
@@ -15,6 +14,7 @@
"ia": "yarn install-app",
"install-app": "cd ../common && yarn && cd ../app && yarn && cd ios && pod install && cd .. && yarn clean:xcode-env-local",
"ios": "react-native run-ios",
"ios-analyze": "yarn reinstall && react-native-bundle-visualizer --platform ios --dev",
"lint": "eslint .",
"lint:fix": "eslint --fix .",
"nice": "yarn fmt:fix && yarn lint:fix",
@@ -23,38 +23,28 @@
"test": "jest --passWithNoTests"
},
"dependencies": {
"@amplitude/analytics-react-native": "^1.4.7",
"@ethersproject/shims": "^5.7.0",
"@openpassport/zk-kit-lean-imt": "^0.0.6",
"@openpassport/zk-kit-smt": "^0.0.1",
"@peculiar/asn1-schema": "^2.3.15",
"@peculiar/x509": "^1.12.3",
"@react-native-async-storage/async-storage": "^2.1.1",
"@react-native-clipboard/clipboard": "1.13.2",
"@react-native-community/netinfo": "^11.3.3",
"@react-native-google-signin/google-signin": "^13.1.0",
"@react-navigation/elements": "^2.2.5",
"@react-navigation/native": "^7.0.14",
"@react-navigation/native-stack": "^7.2.0",
"@react-navigation/stack": "^7.1.1",
"@segment/analytics-react-native": "^2.20.3",
"@segment/sovran-react-native": "^1.1.3",
"@stablelib/cbor": "^2.0.1",
"@tamagui/colors": "1.110.0",
"@tamagui/config": "1.110.0",
"@tamagui/lucide-icons": "1.110.0",
"@tamagui/toast": "1.110.0",
"@tamagui/types": "1.110.0",
"asn1.js": "^5.4.1",
"axios": "^1.6.3",
"asn1js": "^3.0.5",
"burnt": "^0.12.2",
"country-emoji": "^1.5.6",
"country-iso-3-to-2": "^1.1.1",
"elliptic": "^6.6.1",
"ethers": "^6.11.0",
"events": "^3.3.0",
"expo-modules-core": "^2.2.1",
"js-sha256": "^0.9.0",
"js-sha512": "^0.9.0",
"lottie-react-native": "^7.2.2",
"msgpack-lite": "^0.1.26",
@@ -62,18 +52,13 @@
"pako": "^2.1.0",
"pkijs": "^3.2.4",
"poseidon-lite": "^0.2.0",
"process": "^0.11.10",
"react": "^18.3.1",
"react-native": "0.75.4",
"react-native-biometrics": "^3.0.1",
"react-native-check-version": "^1.3.0",
"react-native-cloud-storage": "^2.2.2",
"react-native-crypto": "^2.2.0",
"react-native-date-picker": "https://github.com/norman-kapschefsky/react-native-date-picker#07b13884e392f386611248bab0f2f9b1093b2f35",
"react-native-device-info": "^14.0.4",
"react-native-dialog": "^9.3.0",
"react-native-dotenv": "^3.4.11",
"react-native-fs": "^2.20.0",
"react-native-gesture-handler": "^2.22.1",
"react-native-get-random-values": "^1.11.0",
"react-native-haptic-feedback": "^2.3.3",
@@ -82,17 +67,13 @@
"react-native-nfc-manager": "^3.15.1",
"react-native-orientation-locker": "^1.7.0",
"react-native-passport-reader": "^1.0.3",
"react-native-randombytes": "^3.6.1",
"react-native-safe-area-context": "^5.2.0",
"react-native-screens": "^4.6.0",
"react-native-svg": "^15.11.1",
"react-native-tracking-transparency": "^0.1.2",
"react-native-zip-archive": "^6.1.0",
"socket.io-client": "^4.7.5",
"stream-browserify": "^3.0.0",
"tamagui": "1.110.0",
"uuid": "^11.0.5",
"ws": "^8.18.0",
"zustand": "^4.5.2"
},
"devDependencies": {
@@ -103,14 +84,10 @@
"@react-native/eslint-config": "0.75.4",
"@react-native/metro-config": "0.75.4",
"@react-native/typescript-config": "0.75.4",
"@tamagui/types": "1.110.0",
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@tsconfig/react-native": "^3.0.0",
"@types/cose-js": "^0",
"@types/crypto-js": "^4.1.1",
"@types/elliptic": "^6",
"@types/events": "^3",
"@types/express": "^4.17.17",
"@types/fast-text-encoding": "^1",
"@types/jest": "^29.5.14",
"@types/msgpack-lite": "^0.1.11",
"@types/node-forge": "^1.3.3",
@@ -118,10 +95,6 @@
"@types/react": "^18.2.6",
"@types/react-native": "^0.73.0",
"@types/react-native-dotenv": "^0.2.0",
"@types/react-test-renderer": "^18.0.0",
"@types/ws": "^8",
"babel-jest": "^29.6.3",
"babel-plugin-module-resolver": "^5.0.2",
"eslint": "^8.19.0",
"jest": "^29.6.3",
"prettier": "2.8.8",

View File

@@ -5,6 +5,7 @@ import { SafeAreaProvider } from 'react-native-safe-area-context';
import {
StaticParamList,
createNavigationContainerRef,
createStaticNavigation,
} from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
@@ -39,6 +40,7 @@ import ShowRecoveryPhraseScreen from './screens/Settings/ShowRecoveryPhraseScree
import SettingsScreen from './screens/SettingsScreen';
import SplashScreen from './screens/SplashScreen';
import StartScreen from './screens/StartScreen';
import useNavigationStore from './stores/navigationStore';
import { black, slate300, white } from './utils/colors';
const AppNavigation = createNativeStackNavigator({
@@ -316,4 +318,25 @@ declare global {
}
}
export default createStaticNavigation(AppNavigation);
// Create a ref that we can use to access the navigation state
export const navigationRef = createNavigationContainerRef();
const Navigation = createStaticNavigation(AppNavigation);
const NavigationWithTracking = () => {
const { trackEvent } = useNavigationStore();
const trackScreenView = () => {
const currentRoute = navigationRef.getCurrentRoute();
if (currentRoute) {
console.log(`Screen View: ${currentRoute.name}`);
trackEvent(`Screen View: ${currentRoute.name}`, {
screenName: currentRoute.name,
params: currentRoute.params,
});
}
};
return <Navigation ref={navigationRef} onStateChange={trackScreenView} />;
};
export default NavigationWithTracking;

View File

@@ -7,6 +7,8 @@ import {
createClient,
} from '@segment/analytics-react-native';
let segmentClient: ReturnType<typeof createClient> | null = null;
class DisableTrackingPlugin extends EventPlugin {
type = PluginType.before;
@@ -36,6 +38,10 @@ export const createSegmentClient = () => {
return null;
}
if (segmentClient) {
return segmentClient;
}
const client = createClient({
writeKey: SEGMENT_KEY,
trackAppLifecycleEvents: true,
@@ -51,6 +57,7 @@ export const createSegmentClient = () => {
});
client.add({ plugin: new DisableTrackingPlugin() });
segmentClient = client;
return client;
};

View File

@@ -1,9 +0,0 @@
import { Text, styled } from 'tamagui';
import { slate500 } from '../../utils/colors';
export const Numerical = styled(Text, {
fontFamily: 'mono',
fontSize: 14,
color: slate500,
});

View File

@@ -13,6 +13,7 @@ import LottieView from 'lottie-react-native';
import { Image } from 'tamagui';
import { initPassportDataParsing } from '../../../../common/src/utils/passports/passport';
import { PassportData } from '../../../../common/src/utils/types';
import passportVerifyAnimation from '../../assets/animations/passport_verify.json';
import ButtonsContainer from '../../components/ButtonsContainer';
import TextsContainer from '../../components/TextsContainer';
@@ -86,10 +87,19 @@ const PassportNFCScanScreen: React.FC<PassportNFCScanScreenProps> = ({}) => {
console.log('NFC Scan Successful');
trackEvent('NFC Scan Successful');
const passportData = parseScanResponse(scanResponse);
const parsedPassportData = initPassportDataParsing(passportData);
await storePassportData(parsedPassportData);
let parsedPassportData: PassportData | null = null;
try {
const passportData = parseScanResponse(scanResponse);
parsedPassportData = initPassportDataParsing(passportData);
} catch (e: any) {
console.error('Parsing NFC Response Unsuccessful');
trackEvent('Parsing NFC Response Unsuccessful', {
error: e.message,
});
return;
}
await storePassportData(parsedPassportData);
const passportMetadata = parsedPassportData.passportMetadata!;
trackEvent('Passport Parsed', {
success: true,

View File

@@ -1,13 +1,15 @@
import { useToastController } from '@tamagui/toast';
import { create } from 'zustand';
import { segmentClient } from '../../App';
import { createSegmentClient } from '../Segment';
interface NavigationState {
toast: ReturnType<typeof useToastController>;
trackEvent: (eventName: string, properties?: Record<string, any>) => void;
}
const segmentClient = createSegmentClient();
const useNavigationStore = create<NavigationState>(() => ({
toast: null as unknown as ReturnType<typeof useToastController>,

View File

@@ -1,82 +0,0 @@
import { NativeModules, Platform } from 'react-native';
import * as amplitude from '@amplitude/analytics-react-native';
import { extractMRZInfo, formatDateToYYMMDD } from './utils';
type Callback = (
error: Error | null,
result?: {
passportNumber: string;
dateOfBirth: string;
dateOfExpiry: string;
},
) => void;
type CancelScan = () => void;
export const startCameraScan = (callback: Callback): CancelScan => {
if (Platform.OS === 'ios') {
NativeModules.MRZScannerModule.startScanning()
.then(
(result: {
documentNumber: string;
birthDate: string;
expiryDate: string;
}) => {
console.log('Scan result:', result);
console.log(
`Document Number: ${result.documentNumber}, Expiry Date: ${result.expiryDate}, Birth Date: ${result.birthDate}`,
);
callback(null, {
passportNumber: result.documentNumber,
dateOfBirth: formatDateToYYMMDD(result.birthDate),
dateOfExpiry: formatDateToYYMMDD(result.expiryDate),
});
},
)
.catch((e: Error) => {
console.error(e);
amplitude.track('camera_scan_error', { error: e });
callback(e as Error);
});
return () => {
// TODO
NativeModules.MRZScannerModule.stopScanning();
};
} else {
NativeModules.CameraActivityModule.startCameraActivity()
.then((mrzInfo: string) => {
try {
const { passportNumber, dateOfBirth, dateOfExpiry } =
extractMRZInfo(mrzInfo);
callback(null, {
passportNumber,
dateOfBirth,
dateOfExpiry,
});
} catch (e) {
console.error('Invalid MRZ format:', (e as Error).message);
amplitude.track('invalid_mrz_format', {
error: (e as Error).message,
});
callback(e as Error);
}
})
.catch((e: Error) => {
console.error('Camera Activity Error:', e);
amplitude.track('camera_scan_error', { error: e.message });
callback(e);
});
return () => {
// TODO
// NativeModules.CameraActivityModule.cancelCameraActivity();
console.log('this would destroy the view');
};
}
};

View File

@@ -1,61 +0,0 @@
import axios from 'axios';
import forge from 'node-forge';
import { contribute_publicKey } from '../../../common/src/constants/constants';
export async function contribute(passportData: any): Promise<void> {
console.log('Contributing...');
const textToEncrypt = JSON.stringify(passportData);
console.log('Text to Encrypt:', textToEncrypt);
try {
const aesKey = forge.random.getBytesSync(32);
const iv = forge.random.getBytesSync(16);
console.log('Generated AES Key (base64):', forge.util.encode64(aesKey));
console.log('Generated IV (base64):', forge.util.encode64(iv));
const cipher = forge.cipher.createCipher('AES-CBC', aesKey);
cipher.start({ iv: iv });
cipher.update(forge.util.createBuffer(textToEncrypt, 'utf8'));
cipher.finish();
const encryptedData = cipher.output.getBytes();
console.log('Encrypted Data (base64):', forge.util.encode64(encryptedData));
const publicKey = forge.pki.publicKeyFromPem(contribute_publicKey);
const encryptedAesKey = publicKey.encrypt(aesKey, 'RSA-OAEP', {
md: forge.md.sha256.create(),
mgf1: {
md: forge.md.sha256.create(),
},
});
const aesKeyBase64 = forge.util.encode64(encryptedAesKey);
const ivBase64 = forge.util.encode64(iv);
const encryptedDataBase64 = forge.util.encode64(encryptedData);
console.log('Encrypted AES Key (base64):', aesKeyBase64);
console.log('Encrypted Data (base64):', encryptedDataBase64);
const data = {
aesKey: aesKeyBase64,
iv: ivBase64,
encryptedData: encryptedDataBase64,
};
console.log('Data to be sent:', JSON.stringify(data));
const response = await axios.post('https://contribute.openpassport.app', {
nullifier: forge.md.sha256
.create()
.update(passportData.encryptedDigest.toString())
.digest()
.toHex(),
data: data,
});
console.log('Server Response:', response.data);
} catch (error) {
console.error('Encryption Error:', error);
}
}

View File

@@ -1,93 +0,0 @@
// import { NativeModules, Platform } from 'react-native';
// import RNFS from 'react-native-fs';
import useNavigationStore from '../stores/navigationStore';
// import { parseProofAndroid } from './utils';
export const generateProof = async (_circuit: string, _inputs: any) => {
// TODO: send to TEE instead
// const startTime = Date.now();
// const { trackEvent } = useNavigationStore.getState();
// trackEvent('Proof Started', {
// success: true,
// circuit: circuit,
// });
// if (!zkey_path || !witness_calculator || !dat_path) {
// trackEvent('Proof Failed', {
// success: false,
// error: 'Required parameters are missing',
// circuit: circuit,
// });
// throw new Error('Required parameters are missing');
// }
// try {
// const response = await NativeModules.Prover.runProveAction(
// zkey_path,
// witness_calculator,
// dat_path,
// inputs,
// );
// if (Platform.OS === 'android') {
// const parsedResponse = parseProofAndroid(response);
// trackEvent('Proof Generated', {
// success: true,
// duration_ms: Date.now() - startTime,
// circuit: circuit,
// });
// return formatProof(parsedResponse);
// } else {
// const parsedResponse = JSON.parse(response);
// trackEvent('Proof Generated', {
// success: true,
// duration_ms: Date.now() - startTime,
// circuit: circuit,
// });
// return formatProof({
// proof: parsedResponse.proof,
// pub_signals: parsedResponse.inputs,
// });
// }
// } catch (err: any) {
// trackEvent('Proof Failed', {
// success: false,
// error: err.message,
// duration_ms: Date.now() - startTime,
// circuit: circuit,
// zkey_path: zkey_path,
// witness_calculator: witness_calculator,
// dat_path: dat_path,
// });
// throw new Error(err);
// }
};
export const formatProof = (rawProof: any): any => {
const { trackEvent } = useNavigationStore.getState();
try {
const formattedProof = {
proof: {
pi_a: [rawProof.proof.a[0], rawProof.proof.a[1], '1'],
pi_b: [
[rawProof.proof.b[0][0], rawProof.proof.b[0][1]],
[rawProof.proof.b[1][0], rawProof.proof.b[1][1]],
['1', '0'],
],
pi_c: [rawProof.proof.c[0], rawProof.proof.c[1], '1'],
protocol: 'groth16',
curve: 'bn128',
},
publicSignals: (rawProof as any).pub_signals,
};
trackEvent('Proof Formatted', {
success: true,
});
return formattedProof;
} catch (err: any) {
trackEvent('Proof FormatFailed', {
success: false,
error: err.message,
});
throw err;
}
};

View File

@@ -1,8 +1,6 @@
import { X509Certificate } from '@peculiar/x509';
import { decode } from '@stablelib/cbor';
//@ts-ignore
import * as asn1 from 'asn1.js';
import * as asn1js from 'asn1js';
import { fromBER } from 'asn1js';
import { Buffer } from 'buffer';
import elliptic from 'elliptic';
import { sha384 } from 'js-sha512';
@@ -15,7 +13,7 @@ import cose from './cose';
/**
* @notice An array specifying the required fields for a valid attestation.
*/
export const requiredFields = [
const requiredFields = [
'module_id',
'digest',
'timestamp',
@@ -24,32 +22,6 @@ export const requiredFields = [
'cabundle',
];
/**
* @notice ASN.1 context interface for use with asn1js.js.
*/
interface ASN1Context {
seq(): ASN1Context;
obj(...args: any[]): ASN1Context;
key(name: string): ASN1Context;
objid(): ASN1Context;
bitstr(): ASN1Context;
}
/**
* @notice ASN.1 definition for an Elliptic Curve Public Key.
*/
export const ECPublicKeyASN = asn1.define(
'ECPublicKey',
function (this: ASN1Context) {
this.seq().obj(
this.key('algo')
.seq()
.obj(this.key('id').objid(), this.key('curve').objid()),
this.key('pubKey').bitstr(),
);
},
);
/**
* @notice Utility function to check if a number is within (start, end] range.
* @param start The start of the range (exclusive).
@@ -239,7 +211,7 @@ export function getPublicKey(attestation: Array<number>) {
* @return The PEM-formatted certificate string.
* @throws Error if the conversion fails.
*/
export function derToPem(der: Buffer): string {
function derToPem(der: Buffer): string {
try {
const base64 = Buffer.from(der).toString('base64');
return (
@@ -260,7 +232,7 @@ export function derToPem(der: Buffer): string {
* @throws Error if the COSE_Sign1 format is invalid or PCR0 is missing/incorrect.
* @see https://docs.aws.amazon.com/enclaves/latest/user/set-up-attestation.html
*/
export function getImageHash(attestation: Array<number>) {
function getImageHash(attestation: Array<number>) {
const coseSign1 = decode(Buffer.from(attestation));
if (!Array.isArray(coseSign1) || coseSign1.length !== 4) {
@@ -326,9 +298,9 @@ function getPublicKeyFromPem(pem: string) {
* @param pemContent A string containing the PEM formatted certificate including header/footer markers.
* @return A Certificate object parsed from the PEM content.
* @dev The function strips the PEM header/footer and line breaks, decodes the base64 content into binary,
* creates an ArrayBuffer, and then parses the ASN.1 structure using asn1js.fromBER. Throws an error if parsing fails.
* creates an ArrayBuffer, and then parses the ASN.1 structure using fromBER. Throws an error if parsing fails.
*/
export function getCertificateFromPem(pemContent: string): Certificate {
function getCertificateFromPem(pemContent: string): Certificate {
const pemFormatted = pemContent.replace(
/(-----(BEGIN|END) CERTIFICATE-----|\n|\r)/g,
'',
@@ -340,7 +312,7 @@ export function getCertificateFromPem(pemContent: string): Certificate {
view[i] = binary[i];
}
const asn1Data = asn1js.fromBER(arrayBuffer);
const asn1Data = fromBER(arrayBuffer);
if (asn1Data.offset === -1) {
throw new Error(`ASN.1 parsing error: ${asn1Data.result.error}`);
}
@@ -353,7 +325,7 @@ function verifyCertificateSignature(child: string, parent: string): boolean {
parent.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''),
'base64',
);
const asn1Data_csca = asn1js.fromBER(certBuffer_csca);
const asn1Data_csca = fromBER(certBuffer_csca);
const cert_csca = new Certificate({ schema: asn1Data_csca.result });
const publicKeyInfo_csca = cert_csca.subjectPublicKeyInfo;
const publicKeyBuffer_csca =
@@ -368,19 +340,19 @@ function verifyCertificateSignature(child: string, parent: string): boolean {
child.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''),
'base64',
);
const asn1Data_dsc = asn1js.fromBER(certBuffer_dsc);
const asn1Data_dsc = fromBER(certBuffer_dsc);
const cert_dsc = new Certificate({ schema: asn1Data_dsc.result });
const signatureValue = cert_dsc.signatureValue.valueBlock.valueHexView;
const signature_crypto = Buffer.from(signatureValue).toString('hex');
return key_csca.verify(tbsHash, signature_crypto);
}
export function getTBSHash(pem: string): string {
function getTBSHash(pem: string): string {
const certBuffer = Buffer.from(
pem.replace(/(-----(BEGIN|END) CERTIFICATE-----|\n)/g, ''),
'base64',
);
const asn1Data_cert = asn1js.fromBER(certBuffer);
const asn1Data_cert = fromBER(certBuffer);
const cert = new Certificate({ schema: asn1Data_cert.result });
const tbsAsn1 = cert.encodeTBS();
const tbsDer = tbsAsn1.toBER(false);

View File

@@ -1,7 +1,7 @@
import { Linking } from 'react-native';
import msgpack from 'msgpack-lite';
import pako from 'pako';
import { decode } from 'msgpack-lite';
import { inflate } from 'pako';
import { SelfApp } from '../../../common/src/utils/appType';
import useNavigationStore from '../stores/navigationStore';
@@ -18,8 +18,8 @@ export default async function handleQRCodeScan(
const uint8Array = new Uint8Array(
decodedResult.split('').map(char => char.charCodeAt(0)),
);
const decompressedData = pako.inflate(uint8Array);
const unpackedData = msgpack.decode(decompressedData);
const decompressedData = inflate(uint8Array);
const unpackedData = decode(decompressedData);
const openPassportApp: SelfApp = unpackedData;
setApp(openPassportApp);

View File

@@ -1,55 +0,0 @@
// utils from snarkjs copied here before snarkjs imports node crypto
function unstringifyBigInts(o: any): any {
if (typeof o === 'string' && /^[0-9]+$/.test(o)) {
return BigInt(o);
} else if (typeof o === 'string' && /^0x[0-9a-fA-F]+$/.test(o)) {
return BigInt(o);
} else if (Array.isArray(o)) {
return o.map(unstringifyBigInts);
} else if (typeof o === 'object') {
if (o === null) {
return null;
}
const res: any = {};
const keys = Object.keys(o);
keys.forEach(k => {
res[k] = unstringifyBigInts(o[k]);
});
return res;
} else {
return o;
}
}
function p256(n: any) {
let nstr = n.toString(16);
while (nstr.length < 64) {
nstr = '0' + nstr;
}
nstr = `"0x${nstr}"`;
return nstr;
}
export default function groth16ExportSolidityCallData(_proof: any, _pub: any) {
const proof = unstringifyBigInts(_proof);
const pub = unstringifyBigInts(_pub);
let inputs = '';
for (let i = 0; i < pub.length; i++) {
if (inputs !== '') {
inputs = inputs + ',';
}
inputs = inputs + p256(pub[i]);
}
const S =
`[${p256(proof.a[0])}, ${p256(proof.a[1])}],` +
`[[${p256(proof.b[0][1])}, ${p256(proof.b[0][0])}],[${p256(
proof.b[1][1],
)}, ${p256(proof.b[1][0])}]],` +
`[${p256(proof.c[0])}, ${p256(proof.c[1])}],` +
`[${inputs}]`;
return S;
}

View File

@@ -1,7 +1,3 @@
// Function to extract information from a two-line MRZ.
import { countryCodes } from '../../../common/src/constants/constants';
import { Proof } from '../../../common/src/utils/types';
// The actual parsing would depend on the standard being used (TD1, TD2, TD3, MRVA, MRVB).
export function extractMRZInfo(mrzString: string) {
const mrzLines = mrzString.split('\n');
@@ -32,69 +28,6 @@ export function formatDateToYYMMDD(inputDate: string) {
return year + month + day;
}
export const ModalProofSteps = {
MODAL_REQUEST_SENT: 1,
MODAL_SERVER_ERROR: 2,
MODAL_SERVER_SUCCESS: 3,
};
export function formatAttribute(key: string, attribute: string) {
if (key === 'expiry_date') {
const year = '20' + attribute.substring(0, 2); // Assuming all expiry dates are in the 2000s
const month = attribute.substring(2, 4);
const day = attribute.substring(4, 6);
return `${year}-${month}-${day}`; // ISO 8601 format (YYYY-MM-DD)
} else if (key === 'nationality' && attribute in countryCodes) {
return countryCodes[attribute as keyof typeof countryCodes];
} else if (key === 'date_of_birth') {
let year = '19' + attribute.substring(0, 2);
const currentYear = 2024;
const birthYear = parseInt(year); // eslint-disable-line radix
if (currentYear - birthYear > 100) {
year = '20' + attribute.substring(0, 2);
}
const month = attribute.substring(2, 4);
const day = attribute.substring(4, 6);
return `${year}-${month}-${day}`; // ISO 8601 format (YYYY-MM-DD)
}
return attribute;
}
export const parseProofAndroid = (response: string) => {
const match = response.match(
/ZkProof\(proof=Proof\(pi_a=\[(.*?)\], pi_b=\[\[(.*?)\], \[(.*?)\], \[1, 0\]\], pi_c=\[(.*?)\], protocol=groth16, curve=bn128\), pub_signals=\[(.*?)\]\)/,
);
if (!match) {
throw new Error('Invalid input format');
}
const [, pi_a, pi_b_1, pi_b_2, pi_c, pub_signals] = match;
return {
proof: {
a: pi_a.split(',').map((n: string) => n.trim()),
b: [
pi_b_1.split(',').map((n: string) => n.trim()),
pi_b_2.split(',').map((n: string) => n.trim()),
],
c: pi_c.split(',').map((n: string) => n.trim()),
},
pub_signals: pub_signals.split(',').map((n: string) => n.trim()),
} as Proof;
};
export function getFirstName(mrz: string): string {
try {
const names = mrz.split('<<');
const firstName = names[1].split('<')[0].trim();
const capitalized = firstName.charAt(0) + firstName.slice(1).toLowerCase();
return capitalized || 'Unknown';
} catch (error) {
return '';
}
}
export function checkScannedInfo(
passportNumber: string,
dateOfBirth: string,
@@ -111,11 +44,3 @@ export function checkScannedInfo(
}
return true;
}
export const maskString = (input: string): string => {
if (input.length <= 5) {
return input.charAt(0) + '*'.repeat(input.length - 1);
} else {
return input.charAt(0) + input.charAt(1) + '*'.repeat(input.length - 2);
}
};

File diff suppressed because it is too large Load Diff