chore: export credentials individually

This commit is contained in:
Danish Arora 2025-04-02 16:26:56 +05:30
parent ecb136a612
commit ff894d6464
No known key found for this signature in database
GPG Key ID: 1C6EF37CDAE1426E
2 changed files with 71 additions and 29 deletions

View File

@ -1,6 +1,6 @@
"use client";
import React from 'react';
import React, { useState } from 'react';
import { useKeystore } from '../../../contexts/keystore';
import { useAppState } from '../../../contexts/AppStateContext';
import { useRLN } from '../../../contexts/rln';
@ -9,14 +9,16 @@ import { saveKeystoreToFile, readKeystoreFromFile } from '../../../utils/fileUti
export function KeystoreManagement() {
const {
hasStoredCredentials,
storedCredentialsHashes,
storedCredentialsHashes,
error,
exportKeystore,
exportCredential,
importKeystore,
removeCredential
} = useKeystore();
const { setGlobalError } = useAppState();
const { isInitialized, isStarted } = useRLN();
const [exportPassword, setExportPassword] = useState<string>('');
const [selectedCredential, setSelectedCredential] = useState<string | null>(null);
React.useEffect(() => {
if (error) {
@ -24,12 +26,18 @@ export function KeystoreManagement() {
}
}, [error, setGlobalError]);
const handleExport = () => {
const handleExportCredential = async (hash: string) => {
try {
const keystoreJson = exportKeystore();
saveKeystoreToFile(keystoreJson);
if (!exportPassword) {
setGlobalError('Please enter your keystore password to export');
return;
}
const keystoreJson = await exportCredential(hash, exportPassword);
saveKeystoreToFile(keystoreJson, `waku-rln-credential-${hash.slice(0, 8)}.json`);
setExportPassword('');
setSelectedCredential(null);
} catch (err) {
setGlobalError(err instanceof Error ? err.message : 'Failed to export keystore');
setGlobalError(err instanceof Error ? err.message : 'Failed to export credential');
}
};
@ -61,14 +69,8 @@ export function KeystoreManagement() {
</h2>
<div className="space-y-6">
{/* Import/Export Actions */}
<div className="flex space-x-4">
<button
onClick={handleExport}
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800"
>
Export Keystore
</button>
{/* Import Action */}
<div>
<button
onClick={handleImport}
className="px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800"
@ -99,16 +101,44 @@ export function KeystoreManagement() {
key={hash}
className="p-4 rounded-lg border border-gray-200 dark:border-gray-700"
>
<div className="flex items-start justify-between">
<code className="text-sm text-gray-600 dark:text-gray-400 break-all">
{hash}
</code>
<button
onClick={() => handleRemoveCredential(hash)}
className="ml-4 text-red-600 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300"
>
Remove
</button>
<div className="flex flex-col space-y-3">
<div className="flex items-start justify-between">
<code className="text-sm text-gray-600 dark:text-gray-400 break-all">
{hash}
</code>
<div className="flex space-x-2">
<button
onClick={() => setSelectedCredential(hash === selectedCredential ? null : hash)}
className="text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
>
Export
</button>
<button
onClick={() => handleRemoveCredential(hash)}
className="text-red-600 hover:text-red-700 dark:text-red-400 dark:hover:text-red-300"
>
Remove
</button>
</div>
</div>
{selectedCredential === hash && (
<div className="mt-2 space-y-2">
<input
type="password"
value={exportPassword}
onChange={(e) => setExportPassword(e.target.value)}
placeholder="Enter keystore password"
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100"
/>
<button
onClick={() => handleExportCredential(hash)}
className="w-full px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 dark:focus:ring-offset-gray-800"
>
Export Credential
</button>
</div>
)}
</div>
</div>
))}

View File

@ -11,7 +11,7 @@ interface KeystoreContextType {
hasStoredCredentials: boolean;
storedCredentialsHashes: string[];
saveCredentials: (credentials: KeystoreEntity, password: string) => Promise<string>;
exportKeystore: () => string;
exportCredential: (hash: string, password: string) => Promise<string>;
importKeystore: (keystoreJson: string) => boolean;
removeCredential: (hash: string) => void;
}
@ -82,12 +82,24 @@ export function KeystoreProvider({ children }: { children: ReactNode }) {
}
};
const exportKeystore = (): string => {
const exportCredential = async (hash: string, password: string): Promise<string> => {
if (!keystore) {
throw new Error("Keystore not initialized");
}
return keystore.toString();
// Create a new keystore instance for the single credential
const singleCredentialKeystore = Keystore.create();
// Get the credential from the main keystore
const credential = await keystore.readCredential(hash, password);
if (!credential) {
throw new Error("Credential not found");
}
// Add the credential to the new keystore
await singleCredentialKeystore.addCredential(credential, password);
return singleCredentialKeystore.toString();
};
const importKeystore = (keystoreJson: string): boolean => {
@ -124,7 +136,7 @@ export function KeystoreProvider({ children }: { children: ReactNode }) {
hasStoredCredentials: storedCredentialsHashes.length > 0,
storedCredentialsHashes,
saveCredentials,
exportKeystore,
exportCredential,
importKeystore,
removeCredential
};