move clearPassportData, markCurrentDocumentAsRegistered, reStorePassportDataWithRightCSCA to SDK (#1041)

This commit is contained in:
Leszek Stachowski
2025-09-11 15:48:12 +02:00
committed by GitHub
parent 4db3734b75
commit f416211037
14 changed files with 258 additions and 95 deletions

View File

@@ -40,7 +40,6 @@
* - Display format determined by documentCategory
*/
import { sha256 } from 'js-sha256';
import type { PropsWithChildren } from 'react';
import React, { createContext, useCallback, useContext, useMemo } from 'react';
import Keychain from 'react-native-keychain';
@@ -51,11 +50,12 @@ import type {
} from '@selfxyz/common/utils';
import {
brutforceSignatureAlgorithmDsc,
calculateContentHash,
inferDocumentCategory,
parseCertificateSimple,
} from '@selfxyz/common/utils';
import type {
DocumentCatalog,
DocumentCategory,
DocumentMetadata,
PassportData,
} from '@selfxyz/common/utils/types';
@@ -113,35 +113,6 @@ const notifyDocumentChange = (isMock: boolean) => {
// ===== NEW STORAGE IMPLEMENTATION =====
function calculateContentHash(passportData: PassportData): string {
if (passportData.eContent) {
// eContent is likely a buffer or array, convert to string properly
const eContentStr =
typeof passportData.eContent === 'string'
? passportData.eContent
: JSON.stringify(passportData.eContent);
return sha256(eContentStr);
}
// For documents without eContent (like aadhaar), hash core stable fields
const stableData = {
documentType: passportData.documentType,
data: passportData.mrz || '', // Use mrz for passports/IDs, could be other data for aadhaar
documentCategory: passportData.documentCategory,
};
return sha256(JSON.stringify(stableData));
}
function inferDocumentCategory(documentType: string): DocumentCategory {
if (documentType.includes('passport')) {
return 'passport' as DocumentCategory;
} else if (documentType.includes('id')) {
return 'id_card' as DocumentCategory;
} else if (documentType.includes('aadhaar')) {
return 'aadhaar' as DocumentCategory;
}
return 'passport' as DocumentCategory; // fallback
}
// Global flag to track if native modules are ready
let nativeModulesReady = false;
@@ -153,7 +124,6 @@ export const PassportContext = createContext<IPassportContext>({
setData: storePassportData,
getPassportDataAndSecret: () => Promise.resolve(null),
getSelectedPassportDataAndSecret: () => Promise.resolve(null),
clearPassportData: clearPassportData,
clearSpecificData: clearSpecificPassportData,
loadDocumentCatalog: safeLoadDocumentCatalog,
getAllDocuments: () => Promise.resolve({}),
@@ -163,7 +133,6 @@ export const PassportContext = createContext<IPassportContext>({
getCurrentDocumentType: getCurrentDocumentType,
clearDocumentCatalogForMigrationTesting:
clearDocumentCatalogForMigrationTesting,
markCurrentDocumentAsRegistered: markCurrentDocumentAsRegistered,
updateDocumentRegistrationState: updateDocumentRegistrationState,
checkIfAnyDocumentsNeedMigration: checkIfAnyDocumentsNeedMigration,
checkAndUpdateRegistrationStates: checkAndUpdateRegistrationStates,
@@ -217,7 +186,6 @@ export const PassportProvider = ({ children }: PassportProviderProps) => {
setData: storePassportData,
getPassportDataAndSecret,
getSelectedPassportDataAndSecret,
clearPassportData: clearPassportData,
clearSpecificData: clearSpecificPassportData,
loadDocumentCatalog: safeLoadDocumentCatalog,
getAllDocuments: () => safeGetAllDocuments(selfClient),
@@ -227,7 +195,6 @@ export const PassportProvider = ({ children }: PassportProviderProps) => {
getCurrentDocumentType: getCurrentDocumentType,
clearDocumentCatalogForMigrationTesting:
clearDocumentCatalogForMigrationTesting,
markCurrentDocumentAsRegistered: markCurrentDocumentAsRegistered,
updateDocumentRegistrationState: updateDocumentRegistrationState,
checkIfAnyDocumentsNeedMigration: checkIfAnyDocumentsNeedMigration,
checkAndUpdateRegistrationStates: checkAndUpdateRegistrationStates,
@@ -296,22 +263,6 @@ export async function clearDocumentCatalogForMigrationTesting() {
);
}
export async function clearPassportData() {
const catalog = await loadDocumentCatalogDirectlyFromKeychain();
// Delete all documents
for (const doc of catalog.documents) {
try {
await Keychain.resetGenericPassword({ service: `document-${doc.id}` });
} catch {
console.log(`Document ${doc.id} not found or already cleared`);
}
}
// Clear catalog
await saveDocumentCatalogDirectlyToKeychain({ documents: [] });
}
export async function clearSpecificPassportData(documentType: string) {
const catalog = await loadDocumentCatalogDirectlyFromKeychain();
const docsToDelete = catalog.documents.filter(
@@ -323,6 +274,12 @@ export async function clearSpecificPassportData(documentType: string) {
}
}
export async function deleteDocumentDirectlyFromKeychain(
documentId: string,
): Promise<void> {
await Keychain.resetGenericPassword({ service: `document-${documentId}` });
}
export async function deleteDocument(documentId: string): Promise<void> {
const catalog = await loadDocumentCatalogDirectlyFromKeychain();
@@ -472,6 +429,8 @@ export const selfClientDocumentsAdapter: DocumentsAdapter = {
loadDocumentCatalog: loadDocumentCatalogDirectlyFromKeychain,
loadDocumentById: loadDocumentByIdDirectlyFromKeychain,
saveDocumentCatalog: saveDocumentCatalogDirectlyToKeychain,
deleteDocument: deleteDocumentDirectlyFromKeychain,
saveDocument: storeDocumentDirectlyToKeychain,
};
export async function loadDocumentCatalogDirectlyFromKeychain(): Promise<DocumentCatalog> {
@@ -653,7 +612,6 @@ interface IPassportContext {
data: { passportData: PassportData; secret: string };
signature: string;
} | null>;
clearPassportData: () => Promise<void>;
clearSpecificData: (documentType: string) => Promise<void>;
loadDocumentCatalog: () => Promise<DocumentCatalog>;
@@ -667,7 +625,6 @@ interface IPassportContext {
migrateFromLegacyStorage: () => Promise<void>;
getCurrentDocumentType: () => Promise<string | null>;
clearDocumentCatalogForMigrationTesting: () => Promise<void>;
markCurrentDocumentAsRegistered: () => Promise<void>;
updateDocumentRegistrationState: (
documentId: string,
isRegistered: boolean,
@@ -676,15 +633,6 @@ interface IPassportContext {
checkAndUpdateRegistrationStates: () => Promise<void>;
}
export async function markCurrentDocumentAsRegistered(): Promise<void> {
const catalog = await loadDocumentCatalogDirectlyFromKeychain();
if (catalog.selectedDocumentId) {
await updateDocumentRegistrationState(catalog.selectedDocumentId, true);
} else {
console.warn('No selected document to mark as registered');
}
}
export async function migrateFromLegacyStorage(): Promise<void> {
console.log('Migrating from legacy storage to new architecture...');
const catalog = await loadDocumentCatalogDirectlyFromKeychain();
@@ -792,6 +740,15 @@ export async function setSelectedDocument(documentId: string): Promise<void> {
}
}
async function storeDocumentDirectlyToKeychain(
contentHash: string,
passportData: PassportData,
): Promise<void> {
await Keychain.setGenericPassword(contentHash, JSON.stringify(passportData), {
service: `document-${contentHash}`,
});
}
export async function storeDocumentWithDeduplication(
passportData: PassportData,
): Promise<string> {
@@ -806,13 +763,7 @@ export async function storeDocumentWithDeduplication(
console.log('Document with same content exists, updating stored data');
// Update the stored document with potentially new metadata
await Keychain.setGenericPassword(
contentHash,
JSON.stringify(passportData),
{
service: `document-${contentHash}`,
},
);
await storeDocumentDirectlyToKeychain(contentHash, passportData);
// Update selected document to this one
catalog.selectedDocumentId = contentHash;
@@ -821,9 +772,7 @@ export async function storeDocumentWithDeduplication(
}
// Store new document using contentHash as service name
await Keychain.setGenericPassword(contentHash, JSON.stringify(passportData), {
service: `document-${contentHash}`,
});
await storeDocumentDirectlyToKeychain(contentHash, passportData);
// Add to catalog
const metadata: DocumentMetadata = {

View File

@@ -37,8 +37,11 @@ import {
getWSDbRelayerUrl,
} from '@selfxyz/common/utils/proving';
import {
clearPassportData,
hasAnyValidRegisteredDocument,
loadSelectedDocument,
markCurrentDocumentAsRegistered,
reStorePassportDataWithRightCSCA,
SdkEvents,
SelfClient,
} from '@selfxyz/mobile-sdk-alpha';
@@ -48,12 +51,6 @@ import {
} from '@selfxyz/mobile-sdk-alpha/constants/analytics';
import { useProtocolStore } from '@selfxyz/mobile-sdk-alpha/stores';
// will need to be passed in from selfClient
import {
clearPassportData,
markCurrentDocumentAsRegistered,
reStorePassportDataWithRightCSCA,
} from '@/providers/passportDataProvider';
import { useSelfAppStore } from '@/stores/selfAppStore';
import analytics from '@/utils/analytics';
import { generateTEEInputsDisclose } from '@/utils/proving/provingInputs';
@@ -261,7 +258,7 @@ export const useProvingStore = create<ProvingState>((set, get) => {
if (get().circuitType === 'register') {
(async () => {
try {
await markCurrentDocumentAsRegistered();
await markCurrentDocumentAsRegistered(selfClient);
} catch (error) {
//This will be checked and updated when the app launches the next time
console.error('Error marking document as registered:', error);
@@ -695,7 +692,7 @@ export const useProvingStore = create<ProvingState>((set, get) => {
}
},
validatingDocument: async (_selfClient: SelfClient) => {
validatingDocument: async (selfClient: SelfClient) => {
_checkActorInitialized(actor);
// TODO: for the disclosure, we could check that the selfApp is a valid one.
trackEvent(ProofEvents.VALIDATION_STARTED);
@@ -718,7 +715,9 @@ export const useProvingStore = create<ProvingState>((set, get) => {
status: isSupported.status,
details: isSupported.details,
});
await clearPassportData();
await clearPassportData(selfClient);
actor!.send({ type: 'PASSPORT_NOT_SUPPORTED' });
return;
}
@@ -755,12 +754,16 @@ export const useProvingStore = create<ProvingState>((set, get) => {
},
);
if (isRegistered) {
reStorePassportDataWithRightCSCA(passportData, csca as string);
await reStorePassportDataWithRightCSCA(
selfClient,
passportData,
csca as string,
);
// Mark document as registered since its already onChain
(async () => {
try {
await markCurrentDocumentAsRegistered();
await markCurrentDocumentAsRegistered(selfClient);
} catch (error) {
//it will be checked and marked as registered during next app launch
console.error('Error marking document as registered:', error);