...
This commit is contained in:
@@ -141,12 +141,14 @@ let selectedKeypair = null;
|
||||
let hasEthereumWallet = false;
|
||||
|
||||
// Update UI based on login state
|
||||
function updateLoginUI() {
|
||||
async function updateLoginUI() {
|
||||
const loginStatus = document.getElementById('login-status');
|
||||
|
||||
try {
|
||||
console.log('Ethereum: Checking login status...');
|
||||
// Try to list keypairs to check if logged in
|
||||
const keypairs = list_keypairs();
|
||||
console.log('Ethereum: Keypairs found:', keypairs);
|
||||
|
||||
if (keypairs && keypairs.length > 0) {
|
||||
loginStatus.textContent = 'Status: Logged in';
|
||||
@@ -163,6 +165,7 @@ function updateLoginUI() {
|
||||
hasEthereumWallet = false;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Ethereum: Error checking login status:', e);
|
||||
loginStatus.textContent = 'Status: Not logged in. Please login in the Main Crypto Demo page first.';
|
||||
loginStatus.className = 'status logged-out';
|
||||
|
||||
@@ -449,35 +452,39 @@ const GNOSIS_RPC_URL = "https://rpc.gnosis.gateway.fm";
|
||||
const GNOSIS_EXPLORER = "https://gnosisscan.io";
|
||||
|
||||
async function run() {
|
||||
// Initialize the WebAssembly module
|
||||
await init();
|
||||
|
||||
console.log('WebAssembly crypto module initialized!');
|
||||
|
||||
// Set up the keypair selection
|
||||
document.getElementById('select-keypair').addEventListener('change', performSelectKeypair);
|
||||
|
||||
// Set up the Ethereum wallet management
|
||||
document.getElementById('create-ethereum-wallet-button').addEventListener('click', performCreateEthereumWallet);
|
||||
document.getElementById('create-from-name-button').addEventListener('click', performCreateEthereumWalletFromName);
|
||||
document.getElementById('import-private-key-button').addEventListener('click', performCreateEthereumWalletFromPrivateKey);
|
||||
|
||||
// Set up the copy buttons
|
||||
document.getElementById('copy-address-button').addEventListener('click', () => {
|
||||
const address = document.getElementById('ethereum-address-value').textContent;
|
||||
copyToClipboard(address, 'Ethereum address copied to clipboard!');
|
||||
});
|
||||
|
||||
document.getElementById('copy-private-key-button').addEventListener('click', () => {
|
||||
const privateKey = document.getElementById('ethereum-private-key-value').textContent;
|
||||
copyToClipboard(privateKey, 'Private key copied to clipboard!');
|
||||
});
|
||||
|
||||
// Set up the balance check
|
||||
document.getElementById('check-balance-button').addEventListener('click', checkBalance);
|
||||
|
||||
// Initialize UI
|
||||
updateLoginUI();
|
||||
try {
|
||||
// Initialize the WebAssembly module
|
||||
await init();
|
||||
|
||||
console.log('WebAssembly crypto module initialized!');
|
||||
|
||||
// Set up the keypair selection
|
||||
document.getElementById('select-keypair').addEventListener('change', performSelectKeypair);
|
||||
|
||||
// Set up the Ethereum wallet management
|
||||
document.getElementById('create-ethereum-wallet-button').addEventListener('click', performCreateEthereumWallet);
|
||||
document.getElementById('create-from-name-button').addEventListener('click', performCreateEthereumWalletFromName);
|
||||
document.getElementById('import-private-key-button').addEventListener('click', performCreateEthereumWalletFromPrivateKey);
|
||||
|
||||
// Set up the copy buttons
|
||||
document.getElementById('copy-address-button').addEventListener('click', () => {
|
||||
const address = document.getElementById('ethereum-address-value').textContent;
|
||||
copyToClipboard(address, 'Ethereum address copied to clipboard!');
|
||||
});
|
||||
|
||||
document.getElementById('copy-private-key-button').addEventListener('click', () => {
|
||||
const privateKey = document.getElementById('ethereum-private-key-value').textContent;
|
||||
copyToClipboard(privateKey, 'Private key copied to clipboard!');
|
||||
});
|
||||
|
||||
// Set up the balance check
|
||||
document.getElementById('check-balance-button').addEventListener('click', checkBalance);
|
||||
|
||||
// Initialize UI - call async function and await it
|
||||
await updateLoginUI();
|
||||
} catch (error) {
|
||||
console.error('Error initializing Ethereum page:', error);
|
||||
}
|
||||
}
|
||||
|
||||
run().catch(console.error);
|
285
www/js/index.js
285
www/js/index.js
@@ -19,7 +19,16 @@ import init, {
|
||||
encrypt_symmetric,
|
||||
decrypt_symmetric,
|
||||
encrypt_with_password,
|
||||
decrypt_with_password
|
||||
decrypt_with_password,
|
||||
// KVS functions
|
||||
kv_store_init,
|
||||
kv_store_put,
|
||||
kv_store_get,
|
||||
kv_store_delete,
|
||||
kv_store_exists,
|
||||
kv_store_list_keys,
|
||||
kv_store_put_object,
|
||||
kv_store_get_object
|
||||
} from '../../pkg/webassembly.js';
|
||||
|
||||
// Helper function to convert ArrayBuffer to hex string
|
||||
@@ -70,186 +79,120 @@ function clearAutoLogout() {
|
||||
}
|
||||
}
|
||||
|
||||
// IndexedDB setup and functions
|
||||
// KVS setup and functions
|
||||
const DB_NAME = 'CryptoSpaceDB';
|
||||
const DB_VERSION = 1;
|
||||
const STORE_NAME = 'keySpaces';
|
||||
|
||||
// Initialize the database
|
||||
function initDatabase() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = indexedDB.open(DB_NAME, DB_VERSION);
|
||||
|
||||
request.onerror = (event) => {
|
||||
console.error('Error opening database:', event.target.error);
|
||||
reject('Error opening database: ' + event.target.error);
|
||||
};
|
||||
|
||||
request.onsuccess = (event) => {
|
||||
const db = event.target.result;
|
||||
resolve(db);
|
||||
};
|
||||
|
||||
request.onupgradeneeded = (event) => {
|
||||
const db = event.target.result;
|
||||
// Create object store for key spaces if it doesn't exist
|
||||
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
||||
const store = db.createObjectStore(STORE_NAME, { keyPath: 'name' });
|
||||
store.createIndex('name', 'name', { unique: true });
|
||||
store.createIndex('lastAccessed', 'lastAccessed', { unique: false });
|
||||
}
|
||||
};
|
||||
});
|
||||
async function initDatabase() {
|
||||
try {
|
||||
await kv_store_init(DB_NAME, STORE_NAME);
|
||||
console.log('KV store initialized successfully');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error initializing KV store:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Get database connection
|
||||
function getDB() {
|
||||
return initDatabase();
|
||||
}
|
||||
|
||||
// Save encrypted space to IndexedDB
|
||||
// Save encrypted space to KV store
|
||||
async function saveSpaceToStorage(spaceName, encryptedData) {
|
||||
const db = await getDB();
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction([STORE_NAME], 'readwrite');
|
||||
const store = transaction.objectStore(STORE_NAME);
|
||||
|
||||
try {
|
||||
// Create a space object with metadata
|
||||
const space = {
|
||||
name: spaceName,
|
||||
encryptedData: encryptedData,
|
||||
created: new Date(),
|
||||
lastAccessed: new Date()
|
||||
created: new Date().toISOString(),
|
||||
lastAccessed: new Date().toISOString()
|
||||
};
|
||||
|
||||
const request = store.put(space);
|
||||
// Convert to JSON string
|
||||
const spaceJson = JSON.stringify(space);
|
||||
|
||||
request.onsuccess = () => {
|
||||
resolve();
|
||||
};
|
||||
|
||||
request.onerror = (event) => {
|
||||
console.error('Error saving space:', event.target.error);
|
||||
reject('Error saving space: ' + event.target.error);
|
||||
};
|
||||
|
||||
transaction.oncomplete = () => {
|
||||
db.close();
|
||||
};
|
||||
});
|
||||
// Store in KV store
|
||||
await kv_store_put(DB_NAME, STORE_NAME, spaceName, spaceJson);
|
||||
console.log('Space saved successfully:', spaceName);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error saving space:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Get encrypted space from IndexedDB
|
||||
// Get encrypted space from KV store
|
||||
async function getSpaceFromStorage(spaceName) {
|
||||
try {
|
||||
const db = await getDB();
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction([STORE_NAME], 'readonly');
|
||||
const store = transaction.objectStore(STORE_NAME);
|
||||
const request = store.get(spaceName);
|
||||
|
||||
request.onsuccess = (event) => {
|
||||
const space = event.target.result;
|
||||
if (space) {
|
||||
// Update last accessed timestamp
|
||||
updateLastAccessed(spaceName).catch(console.error);
|
||||
resolve(space.encryptedData);
|
||||
} else {
|
||||
resolve(null);
|
||||
}
|
||||
};
|
||||
|
||||
request.onerror = (event) => {
|
||||
console.error('Error retrieving space:', event.target.error);
|
||||
reject('Error retrieving space: ' + event.target.error);
|
||||
};
|
||||
|
||||
transaction.oncomplete = () => {
|
||||
db.close();
|
||||
};
|
||||
// Get from KV store
|
||||
const spaceJson = await kv_store_get(DB_NAME, STORE_NAME, spaceName);
|
||||
|
||||
if (!spaceJson) {
|
||||
console.log('Space not found:', spaceName);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Parse JSON
|
||||
const space = JSON.parse(spaceJson);
|
||||
|
||||
// Update last accessed timestamp
|
||||
updateLastAccessed(spaceName).catch(console.error);
|
||||
|
||||
// Debug what we're getting back
|
||||
console.log('Retrieved space from KV store with type:', {
|
||||
type: typeof space.encryptedData,
|
||||
length: space.encryptedData ? space.encryptedData.length : 0,
|
||||
isString: typeof space.encryptedData === 'string'
|
||||
});
|
||||
|
||||
return space.encryptedData;
|
||||
} catch (error) {
|
||||
console.error('Database error in getSpaceFromStorage:', error);
|
||||
console.error('Error retrieving space:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Update last accessed timestamp
|
||||
async function updateLastAccessed(spaceName) {
|
||||
const db = await getDB();
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction([STORE_NAME], 'readwrite');
|
||||
const store = transaction.objectStore(STORE_NAME);
|
||||
const request = store.get(spaceName);
|
||||
try {
|
||||
// Get the current space data
|
||||
const spaceJson = await kv_store_get(DB_NAME, STORE_NAME, spaceName);
|
||||
|
||||
request.onsuccess = (event) => {
|
||||
const space = event.target.result;
|
||||
if (space) {
|
||||
space.lastAccessed = new Date();
|
||||
store.put(space);
|
||||
resolve();
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
transaction.oncomplete = () => {
|
||||
db.close();
|
||||
};
|
||||
});
|
||||
if (spaceJson) {
|
||||
// Parse JSON
|
||||
const space = JSON.parse(spaceJson);
|
||||
|
||||
// Update timestamp
|
||||
space.lastAccessed = new Date().toISOString();
|
||||
|
||||
// Save back to KV store
|
||||
await kv_store_put(DB_NAME, STORE_NAME, spaceName, JSON.stringify(space));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error updating last accessed timestamp:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// List all spaces in IndexedDB
|
||||
// List all spaces in KV store
|
||||
async function listSpacesFromStorage() {
|
||||
const db = await getDB();
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction([STORE_NAME], 'readonly');
|
||||
const store = transaction.objectStore(STORE_NAME);
|
||||
const request = store.openCursor();
|
||||
|
||||
const spaces = [];
|
||||
|
||||
request.onsuccess = (event) => {
|
||||
const cursor = event.target.result;
|
||||
if (cursor) {
|
||||
spaces.push(cursor.value.name);
|
||||
cursor.continue();
|
||||
} else {
|
||||
resolve(spaces);
|
||||
}
|
||||
};
|
||||
|
||||
request.onerror = (event) => {
|
||||
console.error('Error listing spaces:', event.target.error);
|
||||
reject('Error listing spaces: ' + event.target.error);
|
||||
};
|
||||
|
||||
transaction.oncomplete = () => {
|
||||
db.close();
|
||||
};
|
||||
});
|
||||
try {
|
||||
// Get all keys with empty prefix (all keys)
|
||||
const keys = await kv_store_list_keys(DB_NAME, STORE_NAME, "");
|
||||
return keys;
|
||||
} catch (error) {
|
||||
console.error('Error listing spaces:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Remove space from IndexedDB
|
||||
// Remove space from KV store
|
||||
async function removeSpaceFromStorage(spaceName) {
|
||||
const db = await getDB();
|
||||
return new Promise((resolve, reject) => {
|
||||
const transaction = db.transaction([STORE_NAME], 'readwrite');
|
||||
const store = transaction.objectStore(STORE_NAME);
|
||||
const request = store.delete(spaceName);
|
||||
|
||||
request.onsuccess = () => {
|
||||
resolve();
|
||||
};
|
||||
|
||||
request.onerror = (event) => {
|
||||
console.error('Error removing space:', event.target.error);
|
||||
reject('Error removing space: ' + event.target.error);
|
||||
};
|
||||
|
||||
transaction.oncomplete = () => {
|
||||
db.close();
|
||||
};
|
||||
});
|
||||
try {
|
||||
await kv_store_delete(DB_NAME, STORE_NAME, spaceName);
|
||||
console.log('Space removed successfully:', spaceName);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error removing space:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Session state
|
||||
@@ -326,24 +269,40 @@ async function performLogin() {
|
||||
document.getElementById('space-result').textContent = 'Loading...';
|
||||
|
||||
// Get encrypted space from IndexedDB
|
||||
console.log('Fetching space from IndexedDB:', spaceName);
|
||||
const encryptedSpace = await getSpaceFromStorage(spaceName);
|
||||
|
||||
if (!encryptedSpace) {
|
||||
console.error('Space not found in IndexedDB:', spaceName);
|
||||
document.getElementById('space-result').textContent = `Space "${spaceName}" not found`;
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Retrieved space from IndexedDB:', { spaceName, encryptedDataLength: encryptedSpace.length });
|
||||
console.log('Retrieved space from IndexedDB:', {
|
||||
spaceName,
|
||||
encryptedDataLength: encryptedSpace.length,
|
||||
encryptedDataType: typeof encryptedSpace
|
||||
});
|
||||
|
||||
try {
|
||||
// Decrypt the space - this is a synchronous WebAssembly function
|
||||
console.log('Attempting to decrypt space with password...');
|
||||
const result = decrypt_key_space(encryptedSpace, password);
|
||||
console.log('Decrypt result:', result);
|
||||
|
||||
if (result === 0) {
|
||||
isLoggedIn = true;
|
||||
currentSpace = spaceName;
|
||||
|
||||
// Save the password in session storage for later use (like when saving)
|
||||
sessionStorage.setItem('currentPassword', password);
|
||||
|
||||
// Update UI and wait for it to complete
|
||||
console.log('Updating UI...');
|
||||
await updateLoginUI();
|
||||
console.log('Updating keypairs list...');
|
||||
updateKeypairsList();
|
||||
|
||||
document.getElementById('space-result').textContent = `Successfully logged in to space "${spaceName}"`;
|
||||
|
||||
// Setup auto-logout
|
||||
@@ -354,6 +313,7 @@ async function performLogin() {
|
||||
document.addEventListener('click', updateActivity);
|
||||
document.addEventListener('keypress', updateActivity);
|
||||
} else {
|
||||
console.error('Failed to decrypt space:', result);
|
||||
document.getElementById('space-result').textContent = `Error logging in: ${result}`;
|
||||
}
|
||||
} catch (decryptErr) {
|
||||
@@ -611,17 +571,32 @@ async function saveCurrentSpace() {
|
||||
if (!isLoggedIn || !currentSpace) return;
|
||||
|
||||
try {
|
||||
// Store the password in a session variable when logging in
|
||||
// and use it here to avoid issues when the password field is cleared
|
||||
const password = document.getElementById('space-password').value;
|
||||
// Get password from session storage (saved during login)
|
||||
const password = sessionStorage.getItem('currentPassword');
|
||||
if (!password) {
|
||||
console.error('Password not available for saving space');
|
||||
alert('Please re-enter your password to save changes');
|
||||
console.error('Password not available in session storage');
|
||||
|
||||
// Fallback to the password field
|
||||
const inputPassword = document.getElementById('space-password').value;
|
||||
if (!inputPassword) {
|
||||
console.error('Password not available for saving space');
|
||||
alert('Please re-enter your password to save changes');
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the input password if session storage isn't available
|
||||
const encryptedSpace = encrypt_key_space(inputPassword);
|
||||
console.log('Saving space with input password');
|
||||
await saveSpaceToStorage(currentSpace, encryptedSpace);
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the password from session storage
|
||||
console.log('Encrypting space with session password');
|
||||
const encryptedSpace = encrypt_key_space(password);
|
||||
console.log('Saving encrypted space to IndexedDB:', currentSpace);
|
||||
await saveSpaceToStorage(currentSpace, encryptedSpace);
|
||||
console.log('Space saved successfully');
|
||||
} catch (e) {
|
||||
console.error('Error saving space:', e);
|
||||
alert('Error saving space: ' + e);
|
||||
|
Reference in New Issue
Block a user