-
Notifications
You must be signed in to change notification settings - Fork 180
Fix nfc configuration scanning issue #978
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,21 +13,21 @@ declare module 'react-native-passport-reader' { | |
| } | ||
|
|
||
| interface PassportReader { | ||
| configure( | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove unused type |
||
| token: string, | ||
| enableDebug?: boolean, | ||
| flushPolicies?: { | ||
| flushInterval?: number; | ||
| flushCount?: number; | ||
| flushOnBackground?: boolean; | ||
| flushOnForeground?: boolean; | ||
| flushOnNetworkChange?: boolean; | ||
| }, | ||
| ): void; | ||
| configure?(token: string, enableDebug?: boolean): void; | ||
| trackEvent?(name: string, properties?: Record<string, unknown>): void; | ||
| flush?(): void; | ||
| reset(): void; | ||
| scan(options: ScanOptions): Promise<{ | ||
| scanPassport( | ||
| passportNumber: string, | ||
| dateOfBirth: string, | ||
| dateOfExpiry: string, | ||
| canNumber: string, | ||
| useCan: boolean, | ||
| skipPACE: boolean, | ||
| skipCA: boolean, | ||
| extendedMode: boolean, | ||
| usePacePolling: boolean, | ||
| ): Promise<{ | ||
| mrz: string; | ||
| eContent: string; | ||
| encryptedDigest: string; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -200,18 +200,24 @@ const flushMixpanelEvents = async () => { | |
| // --- Mixpanel NFC Analytics --- | ||
| export const configureNfcAnalytics = async () => { | ||
| if (!MIXPANEL_NFC_PROJECT_TOKEN || mixpanelConfigured) return; | ||
| const enableDebugLogs = JSON.parse(String(ENABLE_DEBUG_LOGS)); | ||
| if (PassportReader.configure) { | ||
| await Promise.resolve( | ||
| PassportReader.configure(MIXPANEL_NFC_PROJECT_TOKEN, enableDebugLogs, { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hallucination |
||
| flushInterval: 20, | ||
| flushCount: 5, | ||
| flushOnBackground: true, | ||
| flushOnForeground: true, | ||
| flushOnNetworkChange: true, | ||
| }), | ||
| ); | ||
| const enableDebugLogs = | ||
| String(ENABLE_DEBUG_LOGS ?? '') | ||
| .trim() | ||
| .toLowerCase() === 'true'; | ||
|
|
||
| // Check if PassportReader and configure method exist (Android doesn't have configure) | ||
| if (PassportReader && typeof PassportReader.configure === 'function') { | ||
| try { | ||
| // iOS configure method only accepts token and enableDebugLogs | ||
| // Android doesn't have this method at all | ||
| await Promise.resolve( | ||
| PassportReader.configure(MIXPANEL_NFC_PROJECT_TOKEN, enableDebugLogs), | ||
| ); | ||
| } catch (error) { | ||
| console.warn('Failed to configure NFC analytics:', error); | ||
| } | ||
| } | ||
|
|
||
| setupFlushPolicies(); | ||
| mixpanelConfigured = true; | ||
| }; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -183,6 +183,7 @@ interface ProvingState { | |
| endpointType: EndpointType | null; | ||
| fcmToken: string | null; | ||
| env: 'prod' | 'stg' | null; | ||
| selfClient: SelfClient | null; | ||
| setFcmToken: (token: string) => void; | ||
| init: ( | ||
| selfClient: SelfClient, | ||
|
|
@@ -330,6 +331,7 @@ export const useProvingStore = create<ProvingState>((set, get) => { | |
| reason: null, | ||
| endpointType: null, | ||
| fcmToken: null, | ||
| selfClient: null, | ||
| setFcmToken: (token: string) => { | ||
| set({ fcmToken: token }); | ||
| trackEvent(ProofEvents.FCM_TOKEN_STORED); | ||
|
|
@@ -632,6 +634,7 @@ export const useProvingStore = create<ProvingState>((set, get) => { | |
| circuitType, | ||
| endpointType: null, | ||
| env: null, | ||
| selfClient, | ||
| }); | ||
|
|
||
| actor = createActor(provingMachine); | ||
|
|
@@ -649,7 +652,7 @@ export const useProvingStore = create<ProvingState>((set, get) => { | |
|
|
||
| const { data: passportData } = selectedDocument; | ||
|
|
||
| const secret = await selfClient.getPrivateKey(); | ||
| const secret = await get().selfClient?.getPrivateKey(); | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fix test |
||
| if (!secret) { | ||
| console.error('Could not load secret'); | ||
| trackEvent(ProofEvents.LOAD_SECRET_FAILED); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| // SPDX-FileCopyrightText: 2025 Social Connect Labs, Inc. | ||
| // SPDX-License-Identifier: BUSL-1.1 | ||
| // NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE. | ||
|
|
||
| /** | ||
| * Simple contract tests for PassportReader native module | ||
| * These tests verify critical interface requirements without conditional expects | ||
| */ | ||
|
|
||
| import { PassportReader } from 'react-native-passport-reader'; | ||
|
|
||
| describe('PassportReader Simple Contract Tests', () => { | ||
| describe('Critical Interface Requirements', () => { | ||
| it('should have scanPassport method (not scan)', () => { | ||
| // This prevents the iOS "scan is undefined" bug | ||
| expect(PassportReader.scanPassport).toBeDefined(); | ||
| expect(typeof PassportReader.scanPassport).toBe('function'); | ||
| }); | ||
|
|
||
| it('should NOT have scan method', () => { | ||
| // This was the source of the iOS bug | ||
| expect((PassportReader as any).scan).toBeUndefined(); | ||
| }); | ||
|
|
||
| it('should have reset method', () => { | ||
| // This should always exist | ||
| expect(PassportReader.reset).toBeDefined(); | ||
| expect(typeof PassportReader.reset).toBe('function'); | ||
| }); | ||
|
|
||
| it('should have scanPassport with correct parameter count', () => { | ||
| // scanPassport should take exactly 9 parameters | ||
| expect(PassportReader.scanPassport.length).toBe(9); | ||
| }); | ||
|
|
||
| it('should allow configure to be optional', () => { | ||
| // configure might not exist on Android - this should not crash | ||
| const configureType = typeof PassportReader.configure; | ||
| expect(['function', 'undefined']).toContain(configureType); | ||
| }); | ||
|
|
||
| it('should allow trackEvent to be optional', () => { | ||
| // trackEvent might not exist on all platforms | ||
| const trackEventType = typeof PassportReader.trackEvent; | ||
| expect(['function', 'undefined']).toContain(trackEventType); | ||
| }); | ||
|
|
||
| it('should allow flush to be optional', () => { | ||
| // flush might not exist on all platforms | ||
| const flushType = typeof PassportReader.flush; | ||
| expect(['function', 'undefined']).toContain(flushType); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Safe Method Calling Patterns', () => { | ||
| it('should be safe to check configure existence', () => { | ||
| // This pattern should never crash | ||
| expect(() => { | ||
| const hasConfigured = Boolean(PassportReader.configure); | ||
| return hasConfigured; | ||
| }).not.toThrow(); | ||
| }); | ||
|
|
||
| it('should be safe to check trackEvent existence', () => { | ||
| // This pattern should never crash | ||
| expect(() => { | ||
| const hasTrackEvent = Boolean(PassportReader.trackEvent); | ||
| return hasTrackEvent; | ||
| }).not.toThrow(); | ||
| }); | ||
|
|
||
| it('should be safe to check flush existence', () => { | ||
| // This pattern should never crash | ||
| expect(() => { | ||
| const hasFlush = Boolean(PassportReader.flush); | ||
| return hasFlush; | ||
| }).not.toThrow(); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Method Invocation Safety', () => { | ||
| it('should not crash when calling scanPassport', () => { | ||
| // Should be callable (might fail due to missing NFC, but should not crash due to undefined) | ||
| expect(() => { | ||
| PassportReader.scanPassport( | ||
| 'test', | ||
| 'test', | ||
| 'test', | ||
| 'test', | ||
| false, | ||
| false, | ||
| false, | ||
| false, | ||
| false, | ||
| ); | ||
| }).not.toThrow(TypeError); | ||
| }); | ||
|
|
||
| it('should not crash when calling reset', () => { | ||
| // Should be callable | ||
| expect(() => { | ||
| PassportReader.reset(); | ||
| }).not.toThrow(TypeError); | ||
| }); | ||
| }); | ||
|
|
||
| describe('Interface Consistency', () => { | ||
| it('should have consistent method naming', () => { | ||
| // Ensure we use the correct method names | ||
| expect(PassportReader.scanPassport).toBeDefined(); // ✅ Correct | ||
| expect((PassportReader as any).scan).toBeUndefined(); // ❌ Wrong (causes iOS crash) | ||
| }); | ||
|
|
||
| it('should have proper method types', () => { | ||
| // All defined methods should be functions | ||
| expect(typeof PassportReader.reset).toBe('function'); | ||
| expect(typeof PassportReader.scanPassport).toBe('function'); | ||
|
|
||
| // Optional methods should be function or undefined | ||
| expect(['function', 'undefined']).toContain( | ||
| typeof PassportReader.configure, | ||
| ); | ||
| expect(['function', 'undefined']).toContain( | ||
| typeof PassportReader.trackEvent, | ||
| ); | ||
| expect(['function', 'undefined']).toContain(typeof PassportReader.flush); | ||
| }); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missed this ai hallucination....created an unusable typing that doesn't exist anywhere that broke nfc scanning
@seshanthS