Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
59 changes: 59 additions & 0 deletions app/src/hooks/useMockDataForm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// 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.

import { useState } from 'react';

export const useMockDataForm = () => {
const [age, setAge] = useState(21);
const [expiryYears, setExpiryYears] = useState(5);
const [selectedCountry, setSelectedCountry] = useState('USA');
const [selectedAlgorithm, setSelectedAlgorithm] = useState(
Comment on lines +10 to +11
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix nationality default to ISO 3166-1 alpha-2 ("US"), not "USA".

"USA" likely fails downstream validations and can yield non-compliant mock documents.

-  const [selectedCountry, setSelectedCountry] = useState('USA');
+  const [selectedCountry, setSelectedCountry] = useState('US');
@@
-    setSelectedCountry('USA');
+    setSelectedCountry('US');

Also applies to: 25-26

🤖 Prompt for AI Agents
In app/src/hooks/useMockDataForm.ts around lines 10-11 (and also lines 25-26),
the nationality default is set to the three-letter code "USA" which doesn't
conform to ISO 3166-1 alpha-2 and causes downstream validation failures; change
the default value(s) to the two-letter code "US" (update useState initializers
and any hardcoded default constants or mock values at the referenced lines) so
the hook returns ISO-3166-1 alpha-2 compliant country codes.

'sha256 rsa 65537 2048',
);
const [selectedDocumentType, setSelectedDocumentType] = useState<
'mock_passport' | 'mock_id_card'
>('mock_passport');
const [isInOfacList, setIsInOfacList] = useState(true);

const resetFormValues = () => {
setAge(21);
setExpiryYears(5);
setIsInOfacList(true);
setSelectedDocumentType('mock_passport');
Comment on lines +17 to +23
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Do not default to OFAC-listed identity.

Defaulting to isInOfacList=true risks generating sanctioned PII unintentionally in dev flows.

-  const [isInOfacList, setIsInOfacList] = useState(true);
+  const [isInOfacList, setIsInOfacList] = useState(false);
@@
-    setIsInOfacList(true);
+    setIsInOfacList(false);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const [isInOfacList, setIsInOfacList] = useState(true);
const resetFormValues = () => {
setAge(21);
setExpiryYears(5);
setIsInOfacList(true);
setSelectedDocumentType('mock_passport');
const [isInOfacList, setIsInOfacList] = useState(false);
const resetFormValues = () => {
setAge(21);
setExpiryYears(5);
setIsInOfacList(false);
setSelectedDocumentType('mock_passport');
🤖 Prompt for AI Agents
In app/src/hooks/useMockDataForm.ts around lines 17 to 23, the component
currently defaults isInOfacList to true and the resetFormValues handler sets
isInOfacList(true); change the initial useState call to useState(false) and
update resetFormValues to call setIsInOfacList(false) so mock data does not
default to an OFAC-listed identity in dev flows.

setSelectedAlgorithm('sha256 rsa 65537 2048');
setSelectedCountry('USA');
};

const handleCountrySelect = (countryCode: string) => {
setSelectedCountry(countryCode);
};

const handleAlgorithmSelect = (algorithm: string) => {
setSelectedAlgorithm(algorithm);
};

const handleDocumentTypeSelect = (
documentType: 'mock_passport' | 'mock_id_card',
) => {
setSelectedDocumentType(documentType);
};

return {
age,
setAge,
expiryYears,
setExpiryYears,
selectedCountry,
handleCountrySelect,
selectedAlgorithm,
handleAlgorithmSelect,
selectedDocumentType,
handleDocumentTypeSelect,
isInOfacList,
setIsInOfacList,
resetFormValues,
};
};

export default useMockDataForm;
2 changes: 1 addition & 1 deletion app/src/navigation/devTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const devScreens = {
CreateMock: {
screen: MockDataScreen,
options: {
title: 'Mock Passport',
title: 'Mock Document',
headerStyle: {
backgroundColor: black,
},
Expand Down
218 changes: 35 additions & 183 deletions app/src/screens/dev/MockDataScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,17 @@ import { useNavigation } from '@react-navigation/native';
import { ChevronDown, Minus, Plus, X } from '@tamagui/lucide-icons';

import { countryCodes } from '@selfxyz/common/constants';
import type { IdDocInput } from '@selfxyz/common/utils';
import { getSKIPEM } from '@selfxyz/common/utils/csca';
import {
generateMockDSC,
genMockIdDoc,
initPassportDataParsing,
} from '@selfxyz/common/utils/passports';
import { useSelfClient } from '@selfxyz/mobile-sdk-alpha';
generateMockDocument,
signatureAlgorithmToStrictSignatureAlgorithm,
useSelfClient,
} from '@selfxyz/mobile-sdk-alpha';
Comment on lines +27 to +30
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Build break: generateMockDocument is not exported — use generateMockPassport and ensure it’s re-exported in ESM/CJS

CI shows missing export errors for generateMockDocument. The SDK likely exposes generateMockPassport instead; switch the import and usage. Also confirm the SDK’s index.ts and browser.ts re-export it for both ESM and CJS bundles to fix “ENOENT dist/cjs/index.cjs” in tests.

Apply this diff here:

-import {
-  generateMockDocument,
-  signatureAlgorithmToStrictSignatureAlgorithm,
-  useSelfClient,
-} from '@selfxyz/mobile-sdk-alpha';
+import {
+  generateMockPassport,
+  signatureAlgorithmToStrictSignatureAlgorithm,
+  useSelfClient,
+} from '@selfxyz/mobile-sdk-alpha';

Outside this file, ensure the SDK re-exports in both entrypoints (index.ts and browser.ts), for example:

// packages/mobile-sdk-alpha/src/index.ts
export { generateMockPassport } from './mock/generator';

// packages/mobile-sdk-alpha/src/browser.ts
export { generateMockPassport } from './mock/generator';
🧰 Tools
🪛 GitHub Actions: Common CI

[error] 27-27: yarn types: TS2305: Module '@selfxyz/mobile-sdk-alpha' has no exported member 'generateMockDocument'.

🪛 GitHub Actions: Web CI

[error] 27-27: Build failed: No matching export in '../packages/mobile-sdk-alpha/src/index.ts' for import 'generateMockDocument'.


[error] 27-27: Import error: 'generateMockDocument' is not exported by '../packages/mobile-sdk-alpha/dist/esm/browser.js'.

🤖 Prompt for AI Agents
In app/src/screens/dev/MockDataScreen.tsx around lines 27-30, replace the
nonexistent import generateMockDocument with generateMockPassport and update any
usages accordingly; then ensure the SDK package exports generateMockPassport
from its public entrypoints so both ESM and CJS bundles include it (add exports
of generateMockPassport in packages/mobile-sdk-alpha/src/index.ts and
packages/mobile-sdk-alpha/src/browser.ts pointing to the mock/generator). Make
the import change in this file to import generateMockPassport and run the
build/tests to verify the ENOENT dist/cjs/index.cjs export issue is resolved.

import { MockDataEvents } from '@selfxyz/mobile-sdk-alpha/constants/analytics';

import { PrimaryButton } from '@/components/buttons/PrimaryButton';
import ButtonsContainer from '@/components/ButtonsContainer';
import { Caption } from '@/components/typography/Caption';
import { useMockDataForm } from '@/hooks/useMockDataForm';
import SelfDevCard from '@/images/card-dev.svg';
import IdIcon from '@/images/icons/id_icon.svg';
import NoteIcon from '@/images/icons/note.svg';
Expand All @@ -61,92 +59,7 @@ const documentTypes = {
mock_id_card: 'ID Card',
};

const signatureAlgorithmToStrictSignatureAlgorithm = {
'sha256 rsa 65537 4096': ['sha256', 'sha256', 'rsa_sha256_65537_4096'],
'sha1 rsa 65537 2048': ['sha1', 'sha1', 'rsa_sha1_65537_2048'],
'sha256 brainpoolP256r1': [
'sha256',
'sha256',
'ecdsa_sha256_brainpoolP256r1_256',
],
'sha384 brainpoolP384r1': [
'sha384',
'sha384',
'ecdsa_sha384_brainpoolP384r1_384',
],
'sha384 secp384r1': ['sha384', 'sha384', 'ecdsa_sha384_secp384r1_384'],
'sha256 rsa 65537 2048': ['sha256', 'sha256', 'rsa_sha256_65537_2048'],
'sha256 rsa 3 2048': ['sha256', 'sha256', 'rsa_sha256_3_2048'],
'sha256 rsa 65537 3072': ['sha256', 'sha256', 'rsa_sha256_65537_3072'],
'sha256 rsa 3 4096': ['sha256', 'sha256', 'rsa_sha256_3_4096'],
'sha384 rsa 65537 4096': ['sha384', 'sha384', 'rsa_sha384_65537_4096'],
'sha512 rsa 65537 2048': ['sha512', 'sha512', 'rsa_sha512_65537_2048'],
'sha512 rsa 65537 4096': ['sha512', 'sha512', 'rsa_sha512_65537_4096'],
'sha1 rsa 65537 4096': ['sha1', 'sha1', 'rsa_sha1_65537_4096'],
'sha256 rsapss 3 2048': ['sha256', 'sha256', 'rsapss_sha256_3_2048'],
'sha256 rsapss 3 3072': ['sha256', 'sha256', 'rsapss_sha256_3_3072'],
'sha256 rsapss 65537 3072': ['sha256', 'sha256', 'rsapss_sha256_65537_3072'],
'sha256 rsapss 65537 4096': ['sha256', 'sha256', 'rsapss_sha256_65537_4096'],
'sha384 rsapss 65537 2048': ['sha384', 'sha384', 'rsapss_sha384_65537_2048'],
'sha384 rsapss 65537 3072': ['sha384', 'sha384', 'rsapss_sha384_65537_3072'],
'sha512 rsapss 65537 2048': ['sha512', 'sha512', 'rsapss_sha512_65537_2048'],
'sha512 rsapss 65537 4096': ['sha512', 'sha512', 'rsapss_sha512_65537_4096'],
'sha1 secp256r1': ['sha1', 'sha1', 'ecdsa_sha1_secp256r1_256'],
'sha224 secp224r1': ['sha224', 'sha224', 'ecdsa_sha224_secp224r1_224'],
'sha256 secp256r1': ['sha256', 'sha256', 'ecdsa_sha256_secp256r1_256'],
'sha256 secp384r1': ['sha256', 'sha256', 'ecdsa_sha256_secp384r1_384'],
'sha1 brainpoolP224r1': ['sha1', 'sha1', 'ecdsa_sha1_brainpoolP224r1_224'],
'sha1 brainpoolP256r1': ['sha1', 'sha1', 'ecdsa_sha1_brainpoolP256r1_256'],
'sha224 brainpoolP224r1': [
'sha224',
'sha224',
'ecdsa_sha224_brainpoolP224r1_224',
],
'sha256 brainpoolP224r1': [
'sha256',
'sha256',
'ecdsa_sha256_brainpoolP224r1_224',
],
'sha384 brainpoolP256r1': [
'sha384',
'sha384',
'ecdsa_sha384_brainpoolP256r1_256',
],
'sha512 brainpoolP256r1': [
'sha512',
'sha512',
'ecdsa_sha512_brainpoolP256r1_256',
],
'sha512 brainpoolP384r1': [
'sha512',
'sha512',
'ecdsa_sha512_brainpoolP384r1_384',
],
'sha512 poland': ['sha512', 'sha512', 'rsa_sha256_65537_4096'],
'not existing': ['sha512', 'sha384', 'rsa_sha256_65537_4096'],
} as const;

const formatDateToYYMMDD = (date: Date): string => {
return (
date.toISOString().slice(2, 4) +
date.toISOString().slice(5, 7) +
date.toISOString().slice(8, 10)
).toString();
};

const getBirthDateFromAge = (age: number): string => {
const date = new Date();
date.setFullYear(date.getFullYear() - age);
return formatDateToYYMMDD(date);
};

const getExpiryDateFromYears = (years: number): string => {
const date = new Date();
date.setFullYear(date.getFullYear() + years);
return formatDateToYYMMDD(date);
};

const MockPassportTitleCard = () => {
const MockDocumentTitleCard = () => {
return (
<YStack
backgroundColor="#18181B"
Expand All @@ -170,10 +83,10 @@ const MockPassportTitleCard = () => {
</YStack>
<YStack flex={1} flexDirection="column" gap={2}>
<Text fontFamily={dinot} fontWeight={500} fontSize="$6" color={white}>
Generate mock passport data
Generate mock document data
</Text>
<Caption fontFamily={dinot} fontSize="$5" color={zinc400}>
Configure data parameters to generate a mock passport for testing
Configure data parameters to generate a mock document for testing
purposes on the Self Protocol.
</Caption>
</YStack>
Expand All @@ -195,7 +108,7 @@ const HeroBanner = () => {
/>
<YStack zIndex={2}>
<YStack padding="$4">
<MockPassportTitleCard />
<MockDocumentTitleCard />
</YStack>
<YStack
shadowColor={black}
Expand Down Expand Up @@ -246,98 +159,37 @@ const FormSection: React.FC<FormSectionProps> = ({
const MockDataScreen: React.FC = () => {
const { trackEvent } = useSelfClient();
const navigation = useNavigation();
const [age, setAge] = useState(21);
const [expiryYears, setExpiryYears] = useState(5);
const {
age,
setAge,
expiryYears,
setExpiryYears,
selectedCountry,
handleCountrySelect,
selectedAlgorithm,
handleAlgorithmSelect,
selectedDocumentType,
handleDocumentTypeSelect,
isInOfacList,
setIsInOfacList,
resetFormValues,
} = useMockDataForm();
const [isGenerating, setIsGenerating] = useState(false);
const [isInOfacList, setIsInOfacList] = useState(true);
const [selectedDocumentType, setSelectedDocumentType] = useState<
'mock_passport' | 'mock_id_card'
>('mock_passport');
const [selectedCountry, setSelectedCountry] = useState('USA');
const [selectedAlgorithm, setSelectedAlgorithm] = useState(
'sha256 rsa 65537 2048',
);
const [isCountrySheetOpen, setCountrySheetOpen] = useState(false);
const [isAlgorithmSheetOpen, setAlgorithmSheetOpen] = useState(false);
const [isDocumentTypeSheetOpen, setDocumentTypeSheetOpen] = useState(false);

const resetFormValues = () => {
setAge(21);
setExpiryYears(5);
setIsInOfacList(true);
setSelectedDocumentType('mock_passport');
setSelectedAlgorithm('sha256 rsa 65537 2048');
setSelectedCountry('USA');
};

const handleCountrySelect = (countryCode: string) => {
setSelectedCountry(countryCode);
setCountrySheetOpen(false);
};

const handleAlgorithmSelect = (algorithm: string) => {
setSelectedAlgorithm(algorithm);
setAlgorithmSheetOpen(false);
};

const handleDocumentTypeSelect = (
documentType: 'mock_passport' | 'mock_id_card',
) => {
setSelectedDocumentType(documentType);
setDocumentTypeSheetOpen(false);
};

const handleGenerate = useCallback(async () => {
setIsGenerating(true);
try {
const randomPassportNumber = Math.random()
.toString(36)
.substring(2, 11)
.replace(/[^a-z0-9]/gi, '')
.toUpperCase();
const algorithmMapping =
signatureAlgorithmToStrictSignatureAlgorithm[
selectedAlgorithm as keyof typeof signatureAlgorithmToStrictSignatureAlgorithm
];
const dgHashAlgo = algorithmMapping[0];
const eContentHashAlgo = algorithmMapping[1];
const signatureTypeForGeneration = algorithmMapping[2];

const idDocInput: Partial<IdDocInput> = {
nationality: selectedCountry as IdDocInput['nationality'],
idType: selectedDocumentType as IdDocInput['idType'],
dgHashAlgo: dgHashAlgo as IdDocInput['dgHashAlgo'],
eContentHashAlgo: eContentHashAlgo as IdDocInput['eContentHashAlgo'],
signatureType:
signatureTypeForGeneration as IdDocInput['signatureType'],
expiryDate: getExpiryDateFromYears(expiryYears),
passportNumber: randomPassportNumber,
};

let dobForGeneration: string;
if (isInOfacList) {
dobForGeneration = '541007';
idDocInput.lastName = 'HENAO MONTOYA';
idDocInput.firstName = 'ARCANGEL DE JESUS';
} else {
dobForGeneration = getBirthDateFromAge(age);
}
idDocInput.birthDate = dobForGeneration;
let mockDSC, rawMockData;
try {
mockDSC = await generateMockDSC(
idDocInput.signatureType || 'rsa_sha256_65537_2048',
);
rawMockData = genMockIdDoc(idDocInput, mockDSC);
} catch (error) {
console.warn(
'Falling back to default mock DSC. Error during mock DSC generation:',
error,
);
rawMockData = genMockIdDoc(idDocInput);
}
const skiPem = await getSKIPEM('staging');
const parsedMockData = initPassportDataParsing(rawMockData, skiPem);
const parsedMockData = await generateMockDocument({
age,
expiryYears,
isInOfacList,
selectedAlgorithm,
selectedCountry,
selectedDocumentType,
});
await storePassportData(parsedMockData);
Comment on lines +185 to 193
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Call the correct generator and pass a strict algorithm value

Use the SDK’s generator and send the strict value from the mapping, not the display string. This avoids type/validation mismatches in the SDK.

Apply this diff:

-      const parsedMockData = await generateMockDocument({
+      const parsedMockData = await generateMockPassport({
         age,
         expiryYears,
         isInOfacList,
-        selectedAlgorithm,
+        signatureAlgorithm:
+          signatureAlgorithmToStrictSignatureAlgorithm[selectedAlgorithm],
         selectedCountry,
         selectedDocumentType,
       });

Verification script to confirm API name/params and exports:


🏁 Script executed:

#!/bin/bash
# Find generator export(s) and their params
rg -n -C3 -g "packages/mobile-sdk-alpha/**" -e "generateMock(Document|Passport)"
rg -n -C2 -g "packages/mobile-sdk-alpha/**" -e "export .*generateMock(Passport|Document)"
# Check re-exports
rg -n -C2 -g "packages/mobile-sdk-alpha/src/**" -e "export .*generateMockPassport" index.ts browser.ts

Length of output: 18247


🏁 Script executed:

#!/bin/bash
# Search for generateMockDocument occurrences
rg -n -C3 "generateMockDocument"

# Inspect top of MockDataScreen.tsx for imports and usage
sed -n '1,50p' app/src/screens/dev/MockDataScreen.tsx

Length of output: 2673


🏁 Script executed:

#!/bin/bash
sed -n '1,200p' packages/mobile-sdk-alpha/src/mock/generator.ts

Length of output: 5577


Replace generateMockDocument with generateMockPassport
Update the import and invocation—generateMockDocument isn’t exported by the SDK, so calls currently fail. Keep passing selectedAlgorithm (the SDK handles mapping internally). Example diff:

--- a/app/src/screens/dev/MockDataScreen.tsx
+++ b/app/src/screens/dev/MockDataScreen.tsx
@@ -25,7 +25,7 @@
 import { countryCodes } from '@selfxyz/common/constants';
-import { generateMockDocument, signatureAlgorithmToStrictSignatureAlgorithm, useSelfClient } from '@selfxyz/mobile-sdk-alpha';
+import { generateMockPassport, signatureAlgorithmToStrictSignatureAlgorithm, useSelfClient } from '@selfxyz/mobile-sdk-alpha';

 // …

@@ -183,7 +183,7 @@
     try {
-      const parsedMockData = await generateMockDocument({
+      const parsedMockData = await generateMockPassport({
         age,
         expiryYears,
         isInOfacList,
@@ -190,7 +190,7 @@
         selectedCountry,
         selectedDocumentType,
       });
-      await storePassportData(parsedMockData);
+      await storePassportData(parsedMockData);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const parsedMockData = await generateMockDocument({
age,
expiryYears,
isInOfacList,
selectedAlgorithm,
selectedCountry,
selectedDocumentType,
});
await storePassportData(parsedMockData);
// app/src/screens/dev/MockDataScreen.tsx
import { countryCodes } from '@selfxyz/common/constants';
import { generateMockPassport, signatureAlgorithmToStrictSignatureAlgorithm, useSelfClient } from '@selfxyz/mobile-sdk-alpha';
// …
try {
const parsedMockData = await generateMockPassport({
age,
expiryYears,
isInOfacList,
selectedAlgorithm,
selectedCountry,
selectedDocumentType,
});
await storePassportData(parsedMockData);
🤖 Prompt for AI Agents
In app/src/screens/dev/MockDataScreen.tsx around lines 185 to 193, the code
calls generateMockDocument which is not exported by the SDK; replace the call
with generateMockPassport and update the module import at the top of the file to
import generateMockPassport instead of generateMockDocument, keeping
selectedAlgorithm (and the other same args) passed through as before since the
SDK maps the algorithm internally.

navigation.navigate('ConfirmBelongingScreen', {});
} catch (error) {
Expand Down Expand Up @@ -375,7 +227,7 @@ const MockDataScreen: React.FC = () => {
</GestureDetector>
<YStack paddingHorizontal="$4" paddingBottom="$4" gap="$4">
<Text fontWeight={500} fontSize="$6" fontFamily={dinot}>
Mock Passport Parameters
Mock Document Parameters
</Text>
<YStack
borderRadius={10}
Expand Down Expand Up @@ -516,7 +368,7 @@ const MockDataScreen: React.FC = () => {
</XStack>
</FormSection>

<FormSection title="Passport Expires In">
<FormSection title="Document Expires In">
<XStack
alignItems="center"
gap="$2"
Expand Down Expand Up @@ -659,7 +511,7 @@ const MockDataScreen: React.FC = () => {
{isGenerating ? (
<Spinner color="gray" size="small" />
) : (
'Generate Mock Passport'
'Generate Mock Document'
)}
</PrimaryButton>
</ButtonsContainer>
Expand Down
2 changes: 2 additions & 0 deletions packages/mobile-sdk-alpha/src/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ export { defaultConfig } from './config/defaults';
/** @deprecated Use createSelfClient().extractMRZInfo or import from './mrz' */
export { extractMRZInfo, formatDateToYYMMDD, scanMRZ } from './mrz';

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

export { getAllDocuments, hasAnyValidRegisteredDocument, loadSelectedDocument } from './documents/utils';

// Core functions
Expand Down
2 changes: 2 additions & 0 deletions packages/mobile-sdk-alpha/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ export { extractMRZInfo } from './mrz';

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

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

// Documents utils
export { getAllDocuments, hasAnyValidRegisteredDocument, loadSelectedDocument } from './documents/utils';

Expand Down
Loading
Loading