Skip to content
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
ec57382
Improve demo app safe area handling
transphorm Sep 28, 2025
fb824c6
refactor: centralize mobile demo screen navigation
transphorm Sep 28, 2025
dcc04bf
update lock
transphorm Sep 29, 2025
4f170c1
Merge branch 'dev' into codex/review-mobile-sdk-demo-app-for-polish-s…
transphorm Sep 29, 2025
1e1842c
update podfile lock
transphorm Sep 29, 2025
417a428
fix pipelines
transphorm Sep 29, 2025
f848a6f
fix tests
transphorm Sep 30, 2025
cca68fb
save wip polish
transphorm Sep 30, 2025
3d3d434
polish app
transphorm Sep 30, 2025
3b875b4
simplify and standardize screens
transphorm Sep 30, 2025
fe02213
small fixes
transphorm Sep 30, 2025
fc5c4ec
fix tests
transphorm Sep 30, 2025
296d757
Use SDK SelfClientProvider in demo (#1162)
transphorm Sep 30, 2025
dd87f4d
fix types
transphorm Sep 30, 2025
84eb9fc
Fix mobile SDK demo Jest mock
transphorm Sep 30, 2025
7560493
Merge pull request #1164 from selfxyz/codex/fix-failing-pipelines-for…
transphorm Sep 30, 2025
039e6c9
force react-native-svg to 15.12.1
transphorm Sep 30, 2025
0580892
Merge branch 'codex/review-mobile-sdk-demo-app-for-polish-suggestions…
transphorm Sep 30, 2025
0bb30c5
Merge branch 'dev' into codex/review-mobile-sdk-demo-app-for-polish-s…
transphorm Oct 1, 2025
be49dc6
fix tests
transphorm Oct 1, 2025
0c1b322
add types script
transphorm Oct 1, 2025
800cb21
fix document list
transphorm Oct 1, 2025
854d31e
Merge branch 'dev' into codex/review-mobile-sdk-demo-app-for-polish-s…
transphorm Oct 1, 2025
ac33d1f
Merge branch 'dev' into codex/review-mobile-sdk-demo-app-for-polish-s…
transphorm Oct 1, 2025
19e515e
fix types and metro config
transphorm Oct 1, 2025
4071be7
add ignore files to speed up watchman and eslint
transphorm Oct 1, 2025
6602f67
save wip tweaks
transphorm Oct 1, 2025
9f1f556
save mock doc screen wip
transphorm Oct 1, 2025
320c2f7
use persistant document store
transphorm Oct 1, 2025
e12b1c1
save polish work in progress
transphorm Oct 1, 2025
e678847
add polish to screens
transphorm Oct 1, 2025
43c065e
save wip secure storage
transphorm Oct 1, 2025
fb95439
allow cursor to examine react configs
transphorm Oct 1, 2025
fde191d
convert tests to vitest and fix
transphorm Oct 1, 2025
b1959fa
fix tests
transphorm Oct 1, 2025
3ce39ff
prettier
transphorm Oct 1, 2025
1296db8
cr feedback
transphorm Oct 1, 2025
c1a270a
fix tests and remove skipped
transphorm Oct 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .cursorignore
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,6 @@ app/ios/App Thinning Size Report.txt
local.properties
app/android/android-passport-nfc-reader/examples/

# React Native config
app/react-native.config.cjs

# ========================================
# Miscellaneous
# ========================================
Expand Down
15 changes: 15 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
node_modules
dist
build
coverage
ios/build
android/build
android/app/build
app/vendor
circuits/build
contracts/artifacts
contracts/cache
contracts/typechain-types
**/*.js
**/*.cjs
**/*.mjs
10 changes: 10 additions & 0 deletions .watchmanconfig
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
{
"ignore_dirs": [
".git",
".hg",
"node_modules",
"ios/build",
"android/build",
"android/app/build",
"dist",
"build"
]
}
2 changes: 1 addition & 1 deletion app/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ GEM
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.4.0)
aws-partitions (1.1167.0)
aws-partitions (1.1168.0)
aws-sdk-core (3.233.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
Expand Down
12 changes: 6 additions & 6 deletions app/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1520,7 +1520,7 @@ PODS:
- React-Core
- react-native-netinfo (11.4.1):
- React-Core
- react-native-nfc-manager (3.16.3):
- react-native-nfc-manager (3.17.1):
- React-Core
- react-native-safe-area-context (5.6.1):
- DoubleConversion
Expand Down Expand Up @@ -1904,7 +1904,7 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- RNDeviceInfo (14.0.4):
- RNDeviceInfo (14.1.1):
- React-Core
- RNFBApp (19.3.0):
- Firebase/CoreOnly (= 10.24.0)
Expand Down Expand Up @@ -2113,7 +2113,7 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- segment-analytics-react-native (2.21.2):
- segment-analytics-react-native (2.21.3):
- React-Core
- sovran-react-native
- Sentry/HybridSDK (8.53.2)
Expand Down Expand Up @@ -2520,7 +2520,7 @@ SPEC CHECKSUMS:
react-native-cloud-storage: 8d89f2bc574cf11068dfd90933905974087fb9e9
react-native-get-random-values: d16467cf726c618e9c7a8c3c39c31faa2244bbba
react-native-netinfo: cec9c4e86083cb5b6aba0e0711f563e2fbbff187
react-native-nfc-manager: 66a00e5ddab9704efebe19d605b1b8afb0bb1bd7
react-native-nfc-manager: e5e91b4e9af0551755cdb6eaec55a8ff820ccdc6
react-native-safe-area-context: 90a89cb349c7f8168a707e6452288c2f665b9fd1
react-native-sqlite-storage: 0c84826214baaa498796c7e46a5ccc9a82e114ed
React-nativeconfig: 415626a63057638759bcc75e0a96e2e07771a479
Expand Down Expand Up @@ -2552,7 +2552,7 @@ SPEC CHECKSUMS:
ReactCommon: b2eb96a61b826ff327a773a74357b302cf6da678
RNCAsyncStorage: 0003b916f1a69fe2d20b7910e0d08da3d32c7bd6
RNCClipboard: a4827e134e4774e97fa86f7f986694dd89320f13
RNDeviceInfo: d863506092aef7e7af3a1c350c913d867d795047
RNDeviceInfo: bcce8752b5043a623fe3c26789679b473f705d3c
RNFBApp: 4097f75673f8b42a7cd1ba17e6ea85a94b45e4d1
RNFBMessaging: 92325b0d5619ac90ef023a23cfd16fd3b91d0a88
RNFBRemoteConfig: a569bacaa410acfcaba769370e53a787f80fd13b
Expand All @@ -2563,7 +2563,7 @@ SPEC CHECKSUMS:
RNScreens: 806e1449a8ec63c2a4e4cf8a63cc80203ccda9b8
RNSentry: 6ad982be2c8e32dab912afb4132b6a0d88484ea0
RNSVG: 0c1fc3e7b147949dc15644845e9124947ac8c9bb
segment-analytics-react-native: bad4c2c7b63818bd493caa2b5759fca59e4ae9a7
segment-analytics-react-native: a0c29c75ede1989118b50cac96b9495ea5c91a1d
Sentry: 59993bffde4a1ac297ba6d268dc4bbce068d7c1b
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
sovran-react-native: a3ad3f8ff90c2002b2aa9790001a78b0b0a38594
Expand Down
2 changes: 1 addition & 1 deletion app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@
"react-native-safe-area-context": "^5.6.1",
"react-native-screens": "4.15.3",
"react-native-sqlite-storage": "^6.0.1",
"react-native-svg": "^15.12.1",
"react-native-svg": "15.12.1",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lock to this specific version so the build doesn't break

"react-native-svg-circle-country-flags": "^0.2.2",
"react-native-svg-web": "^1.0.9",
"react-native-web": "^0.19.0",
Expand Down
16 changes: 13 additions & 3 deletions app/scripts/mobile-ci-build-android.sh
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,19 @@ fi
# Restore original package files
log "Restoring original package files..."
if [[ -f "package.json.backup" ]] && [[ -f "../yarn.lock.backup" ]]; then
mv package.json.backup package.json
mv ../yarn.lock.backup ../yarn.lock
log "✅ Package files restored successfully"
if mv package.json.backup package.json && mv ../yarn.lock.backup ../yarn.lock; then
log "✅ Package files restored successfully"

# Verify restoration by checking yarn.lock doesn't contain tarball references
if grep -q "file:/tmp/mobile-sdk-alpha-ci.tgz" ../yarn.lock 2>/dev/null; then
log "WARNING: yarn.lock still contains tarball references after restoration"
log "This may cause 'yarn.lock is out of date' errors in CI"
fi
else
log "ERROR: Failed to restore package files"
log "This may cause 'yarn.lock is out of date' errors in CI"
exit 1
fi
else
log "WARNING: Backup files not found - package.json may still reference tarball"
log "Please run 'yarn add @selfxyz/mobile-sdk-alpha@workspace:^' manually"
Expand Down
3 changes: 3 additions & 0 deletions common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ export type {
UserIdType,
} from './src/utils/index.js';

// Additional type exports
export type { Environment } from './src/utils/types.js';

// Constants exports
export type { Country3LetterCode } from './src/constants/index.js';

Expand Down
22 changes: 20 additions & 2 deletions common/src/polyfills/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,14 @@ function createHash(algorithm: string) {
if (typeof data === 'string') {
hasher.update(new TextEncoder().encode(data));
} else {
hasher.update(data);
// Convert Buffer to pure Uint8Array if needed
// Buffer is a subclass of Uint8Array but noble/hashes expects pure Uint8Array
const bytes =
ArrayBuffer.isView(data) &&
!(data instanceof Uint8Array && data.constructor === Uint8Array)
? new Uint8Array(data.buffer, data.byteOffset, data.byteLength)
: data;
hasher.update(bytes);
}
return this;
},
Expand Down Expand Up @@ -96,7 +103,18 @@ function createHmac(algorithm: string, key: string | Uint8Array) {
if (finalized) {
throw new Error('Cannot update after calling digest(). Hash instance has been finalized.');
}
const dataBytes = typeof data === 'string' ? new TextEncoder().encode(data) : data;
let dataBytes: Uint8Array;
if (typeof data === 'string') {
dataBytes = new TextEncoder().encode(data);
} else {
// Convert Buffer to pure Uint8Array if needed
// Buffer is a subclass of Uint8Array but noble/hashes expects pure Uint8Array
dataBytes =
ArrayBuffer.isView(data) &&
!(data instanceof Uint8Array && data.constructor === Uint8Array)
? new Uint8Array(data.buffer, data.byteOffset, data.byteLength)
: data;
}
hmacState.update(dataBytes);
return this;
},
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"resolutions": {
"@babel/core": "^7.28.4",
"@babel/runtime": "^7.28.4",
"@swc/core": "1.7.36",
"@tamagui/animations-react-native": "1.126.14",
"@tamagui/toast": "1.126.14",
"@types/node": "^22.18.3",
Expand Down
1 change: 0 additions & 1 deletion packages/mobile-sdk-alpha/ios/SelfSDK/PassportReader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ class PassportReader: NSObject {
skipCA: skipCABool,
skipPACE: skipPACEBool,
useExtendedMode: extendedModeBool,
usePacePolling: usePacePollingBool,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@seshanthS fyi the demo wouldn't build with this param

customDisplayMessage: customMessageHandler
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ class SelfMRZScannerModule: NSObject, RCTBridgeModule {

@objc func startScanning(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
DispatchQueue.main.async {
guard let rootViewController = UIApplication.shared.keyWindow?.rootViewController else {
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let rootViewController = windowScene.windows.first?.rootViewController else {
reject("error", "Unable to find root view controller", nil)
return
}
Expand Down
2 changes: 1 addition & 1 deletion packages/mobile-sdk-alpha/src/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export { createListenersMap, createSelfClient } from './client';
export { defaultConfig } from './config/defaults';

/** @deprecated Use createSelfClient().extractMRZInfo or import from './mrz' */
export { extractMRZInfo, formatDateToYYMMDD, scanMRZ } from './mrz';
export { extractMRZInfo, extractNameFromMRZ, formatDateToYYMMDD, scanMRZ } from './mrz';

export { generateMockDocument, signatureAlgorithmToStrictSignatureAlgorithm } from './mock/generator';
// Core functions
Expand Down
4 changes: 1 addition & 3 deletions packages/mobile-sdk-alpha/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,7 @@ export { createListenersMap, createSelfClient } from './client';
/** @deprecated Use createSelfClient().extractMRZInfo or import from './mrz' */
export { defaultConfig } from './config/defaults';

export { extractMRZInfo } from './mrz';

export { formatDateToYYMMDD, scanMRZ } from './mrz';
export { extractMRZInfo, extractNameFromMRZ, formatDateToYYMMDD, scanMRZ } from './mrz';

export { generateMockDocument, signatureAlgorithmToStrictSignatureAlgorithm } from './mock/generator';

Expand Down
23 changes: 17 additions & 6 deletions packages/mobile-sdk-alpha/src/mock/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: BUSL-1.1
// NOTE: Converts to Apache-2.0 on 2029-06-11 per LICENSE.

import type { IdDocInput, PassportData } from '@selfxyz/common';
import type { AadhaarData, IdDocInput, PassportData } from '@selfxyz/common';
import { generateMockDSC, genMockIdDoc, getSKIPEM, initPassportDataParsing } from '@selfxyz/common';

export interface GenerateMockDocumentOptions {
Expand All @@ -12,6 +12,8 @@ export interface GenerateMockDocumentOptions {
selectedAlgorithm: string;
selectedCountry: string;
selectedDocumentType: 'mock_passport' | 'mock_id_card' | 'mock_aadhaar';
firstName?: string;
lastName?: string;
}

const formatDateToYYMMDD = (date: Date): string => {
Expand Down Expand Up @@ -48,7 +50,10 @@ export async function generateMockDocument({
selectedAlgorithm,
selectedCountry,
selectedDocumentType,
}: GenerateMockDocumentOptions) {
firstName,
lastName,
}: GenerateMockDocumentOptions): Promise<PassportData | AadhaarData> {
console.log('generateMockDocument received names:', { firstName, lastName, isInOfacList });
const randomPassportNumber = Math.random()
.toString(36)
.substring(2, 11)
Expand All @@ -67,15 +72,19 @@ export async function generateMockDocument({
signatureType: signatureTypeForGeneration as IdDocInput['signatureType'],
expiryDate: getExpiryDateFromYears(expiryYears),
passportNumber: randomPassportNumber,
sex: 'M', // Default value
};

if (selectedDocumentType === 'mock_aadhaar') {
idDocInput.birthDate = getBirthDateFromAge(age, 'DDMMYYYY');

if (isInOfacList) {
idDocInput.lastName = 'HENAO MONTOYA';
idDocInput.firstName = 'ARCANGEL DE JESUS';
idDocInput.lastName = lastName || 'HENAO MONTOYA';
idDocInput.firstName = firstName || 'ARCANGEL DE JESUS';
idDocInput.birthDate = '07-10-1954';
} else {
if (firstName) idDocInput.firstName = firstName;
if (lastName) idDocInput.lastName = lastName;
}

const result = genMockIdDoc(idDocInput);
Expand All @@ -89,10 +98,12 @@ export async function generateMockDocument({
let dobForGeneration: string;
if (isInOfacList) {
dobForGeneration = '541007';
idDocInput.lastName = 'HENAO MONTOYA';
idDocInput.firstName = 'ARCANGEL DE JESUS';
idDocInput.lastName = lastName || 'HENAO MONTOYA';
idDocInput.firstName = firstName || 'ARCANGEL DE JESUS';
} else {
dobForGeneration = getBirthDateFromAge(age);
if (firstName) idDocInput.firstName = firstName;
if (lastName) idDocInput.lastName = lastName;
}
idDocInput.birthDate = dobForGeneration;

Expand Down
2 changes: 1 addition & 1 deletion packages/mobile-sdk-alpha/src/mrz/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import type { ScanResult } from '../types/public';
export type MRZScanOptions = Record<string, never>;

// Re-export processing functions
export { extractMRZInfo, formatDateToYYMMDD } from '../processing/mrz';
export { extractMRZInfo, extractNameFromMRZ, formatDateToYYMMDD } from '../processing/mrz';

/**
* Scan MRZ (Machine Readable Zone) on a passport or ID card.
Expand Down
81 changes: 81 additions & 0 deletions packages/mobile-sdk-alpha/src/processing/mrz.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,87 @@ export function extractMRZInfo(mrzString: string): MRZInfo {
};
}

/**
* Extract name from MRZ string
* Supports TD3 (passport) and TD1 (ID card) formats
*
* @param mrzString - The MRZ data as a string
* @returns Object with firstName and lastName, or null if parsing fails
*
* @example
* ```ts
* const name = extractNameFromMRZ("P<USADOE<<JOHN<<<<<<<<<<<<<<<<<<<<<<<<<");
* // Returns: { firstName: "JOHN", lastName: "DOE" }
* ```
*/
export function extractNameFromMRZ(mrzString: string): { firstName: string; lastName: string } | null {
if (!mrzString || typeof mrzString !== 'string') {
return null;
}

let lines = mrzString
.trim()
.split(/\r?\n/)
.map(line => line.trim())
.filter(Boolean);

// Handle single-line MRZ strings (common for stored data)
// TD3 format: 88 or 90 characters total (2 lines of 44 or 45 chars each)
if (lines.length === 1) {
const mrzLength = lines[0].length;
if (mrzLength === 88 || mrzLength === 90) {
const lineLength = mrzLength === 88 ? 44 : 45;
lines = [lines[0].slice(0, lineLength), lines[0].slice(lineLength)];
}
}

if (lines.length === 0) {
return null;
}

// TD3 format (passport): Name is in line 1 after country code
// Format: P<COUNTRY<<LASTNAME<<FIRSTNAME<<<<<<<<<<
// TD3 typically has 2 lines, first line is usually 44 chars but we'll be lenient
if (lines.length === 2) {
const line1 = lines[0];
const nameMatch = line1.match(/^P<[A-Z]{3}(.+)$/);

if (nameMatch) {
const namePart = nameMatch[1];
// Split by << to separate last name and first name
const parts = namePart.split('<<').filter(Boolean);

if (parts.length >= 2) {
const lastName = parts[0].replace(/<+$/, '').replace(/</g, ' ').trim();
const firstName = parts[1].replace(/<+$/, '').replace(/</g, ' ').trim();
return { firstName, lastName };
} else if (parts.length === 1) {
const name = parts[0].replace(/<+$/, '').replace(/</g, ' ').trim();
return { firstName: '', lastName: name };
}
}
}

// TD1 format (ID card): Name is in line 3
// Format: LASTNAME<<FIRSTNAME<<<<<<<<<<
// TD1 typically has 3 lines, each 30 chars but we'll be lenient
if (lines.length === 3) {
const line3 = lines[2];
const parts = line3.split('<<').filter(Boolean);

if (parts.length >= 2) {
const lastName = parts[0].replace(/<+$/, '').replace(/</g, ' ').trim();
const firstName = parts[1].replace(/<+$/, '').replace(/</g, ' ').trim();
return { firstName, lastName };
} else if (parts.length === 1) {
const name = parts[0].replace(/<+$/, '').replace(/</g, ' ').trim();
return { firstName: '', lastName: name };
}
}

return null;
}

/**
* Format ISO date string (YYYY-MM-DD) to YYMMDD format
* Handles timezone variations and validates input
Expand Down
Loading
Loading