Skip to content

Commit

Permalink
Added multi-key support to ResVault
Browse files Browse the repository at this point in the history
- Now supports adding multiple keys to the same ResVault profile.
- Modified GlobalContext to handle state management.
- Selected keys can now be exported using the download button.
  • Loading branch information
apratimshukla6 committed Oct 10, 2024
1 parent fe26861 commit 6c6d3f6
Show file tree
Hide file tree
Showing 8 changed files with 988 additions and 721 deletions.
35 changes: 21 additions & 14 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,34 @@
/*global chrome*/
import './css/App.css';
import React from 'react';
import React, { useContext } from 'react';
import Home from "./pages/Home";
import SignUp from "./pages/SignUp";
import Login from "./pages/Login";
import Dashboard from "./pages/Dashboard";
import Logs from "./pages/Logs";
import { Navigate, Route, Routes } from "react-router-dom";
import { GlobalProvider } from './context/GlobalContext';
import { Routes, Route, Navigate } from 'react-router-dom';
import { GlobalContext } from './context/GlobalContext';

function App() {
const { isAuthenticated } = useContext(GlobalContext);

return (
<GlobalProvider>
<Routes>
<Route path='/' element={<Home />} />
<Route path='/signup' element={<SignUp />} />
<Route path='/login' element={<Login />} />
<Route path='/dashboard' element={<Dashboard />} />
<Route path='/logs' element={<Logs />} />
<Route path='*' element={<Navigate to='/' />} />
</Routes>
</GlobalProvider>
<Routes>
{!isAuthenticated ? (
<>
<Route path="/" element={<Home />} />
<Route path="/signup" element={<SignUp />} />
<Route path="/login" element={<Login />} />
<Route path="*" element={<Navigate to="/" replace />} />
</>
) : (
<>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="*" element={<Navigate to="/dashboard" replace />} />
</>
)}
</Routes>
);
}

export default App;
export default App;
182 changes: 159 additions & 23 deletions src/context/GlobalContext.js
Original file line number Diff line number Diff line change
@@ -1,57 +1,193 @@
/*global chrome*/
import React, { createContext, useState, useEffect } from 'react';
import CryptoJS from 'crypto-js';
import nacl from 'tweetnacl';
import Base58 from 'bs58';

export const GlobalContext = createContext();

export const GlobalProvider = ({ children }) => {
const [values, setValues] = useState({ password: '', showPassword: false });
const [loginValues, setLoginValues] = useState({ password: '', showPassword: false });
const [confirmValues, setConfirmValues] = useState({ password: '', showPassword: false });
const [transactionData, setTransactionData] = useState({});
const [loginValues, setLoginValues] = useState({ password: '', showPassword: false });
const [publicKey, setPublicKey] = useState('');
const [privateKey, setPrivateKey] = useState('');
const [networks, setNetworks] = useState([]);
const [keyPairs, setKeyPairs] = useState([]);
const [selectedKeyPairIndex, setSelectedKeyPairIndex] = useState(0);
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [storedPassword, setStoredPassword] = useState('');

// Function to encrypt and store key pairs
const saveKeyPairsToStorage = (keyPairs, password) => {
const encryptedKeyPairs = CryptoJS.AES.encrypt(
JSON.stringify(keyPairs),
password
).toString();
chrome.storage.sync.set({ encryptedKeyPairs }, () => {
console.log('Encrypted key pairs saved to storage.');
});
};

// Function to load and decrypt key pairs
const loadKeyPairsFromStorage = (password, callback) => {
chrome.storage.sync.get(['encryptedKeyPairs'], (result) => {
if (result.encryptedKeyPairs) {
try {
const bytes = CryptoJS.AES.decrypt(result.encryptedKeyPairs, password);
const decryptedData = bytes.toString(CryptoJS.enc.Utf8);
const decryptedKeyPairs = JSON.parse(decryptedData);
callback(decryptedKeyPairs);
} catch (err) {
console.error('Error decrypting key pairs:', err);
callback([]);
}
} else {
callback([]);
}
});
};

// Function to save selected key pair index
const saveSelectedKeyPairIndex = (index) => {
chrome.storage.local.set({ selectedKeyPairIndex: index }, () => {});
};

// Function to load selected key pair index
const loadSelectedKeyPairIndex = (callback) => {
chrome.storage.local.get(['selectedKeyPairIndex'], (result) => {
const index = result.selectedKeyPairIndex !== undefined ? result.selectedKeyPairIndex : 0;
callback(index);
});
};

// Function to generate new key pair and store it
const generateKeyPair = (callback) => {
const password = storedPassword;
if (!password) {
console.error('Password is not available');
return;
}

const keyPair = nacl.sign.keyPair();
const newPublicKey = Base58.encode(keyPair.publicKey);
const newPrivateKey = Base58.encode(keyPair.secretKey.slice(0, 32));
const newKeyPair = { publicKey: newPublicKey, privateKey: newPrivateKey };

// Load existing key pairs
loadKeyPairsFromStorage(password, (existingKeyPairs) => {
const updatedKeyPairs = [...existingKeyPairs, newKeyPair];
// Save updated key pairs
saveKeyPairsToStorage(updatedKeyPairs, password);
setKeyPairs(updatedKeyPairs);
setPublicKey(newPublicKey);
setPrivateKey(newPrivateKey);
const newIndex = updatedKeyPairs.length - 1;
setSelectedKeyPairIndex(newIndex);
saveSelectedKeyPairIndex(newIndex);
setIsAuthenticated(true);

// Encrypt the private key and save in 'store'
const encryptedPrivateKey = CryptoJS.AES.encrypt(newPrivateKey, password).toString();
const hash = CryptoJS.SHA256(password).toString(CryptoJS.enc.Hex);
const store = {
hash,
publicKey: newPublicKey,
encryptedPrivateKey: encryptedPrivateKey,
history: [],
};
chrome.storage.sync.set({ store }, () => {
console.log('Store updated with new key pair');
if (callback) {
callback();
}
});
});
};

// Load key pairs from storage when context is initialized
useEffect(() => {
// Retrieve publicKey and encryptedPrivateKey from storage on initialization
chrome.storage.sync.get('store', (data) => {
if (data.store && data.store.publicKey) {
setPublicKey(data.store.publicKey);
chrome.storage.local.get('password', (passwordData) => {
if (passwordData.password) {
const decryptedPrivateKey = CryptoJS.AES.decrypt(
data.store.encryptedPrivateKey,
passwordData.password
).toString(CryptoJS.enc.Utf8);
setPrivateKey(JSON.parse(decryptedPrivateKey));
// Retrieve password from storage
chrome.storage.local.get(['password'], (result) => {
const password = result.password;
if (password) {
setStoredPassword(password);
loadKeyPairsFromStorage(password, (loadedKeyPairs) => {
if (loadedKeyPairs.length > 0) {
setKeyPairs(loadedKeyPairs);
// Load selected key pair index
loadSelectedKeyPairIndex((index) => {
if (loadedKeyPairs[index]) {
setPublicKey(loadedKeyPairs[index].publicKey);
setPrivateKey(loadedKeyPairs[index].privateKey);
setSelectedKeyPairIndex(index);
} else if (loadedKeyPairs.length > 0) {
setPublicKey(loadedKeyPairs[0].publicKey);
setPrivateKey(loadedKeyPairs[0].privateKey);
setSelectedKeyPairIndex(0);
}
setIsAuthenticated(true);
});
} else {
setIsAuthenticated(false);
}
});
} else {
setIsAuthenticated(false);
}
});
}, []);

const updateTransaction = (data) => setTransactionData(data);
const clearData = () => setTransactionData({});
// Function to set selected key pair
const setSelectedKeyPair = (index) => {
if (keyPairs[index]) {
setPublicKey(keyPairs[index].publicKey);
setPrivateKey(keyPairs[index].privateKey);
setSelectedKeyPairIndex(index);
saveSelectedKeyPairIndex(index);

const password = storedPassword;
if (!password) {
console.error('Password is not available');
return;
}
// Encrypt the private key and save in 'store'
const encryptedPrivateKey = CryptoJS.AES.encrypt(keyPairs[index].privateKey, password).toString();
const hash = CryptoJS.SHA256(password).toString(CryptoJS.enc.Hex);
const store = {
hash,
publicKey: keyPairs[index].publicKey,
encryptedPrivateKey: encryptedPrivateKey,
history: [],
};
chrome.storage.sync.set({ store }, () => {
console.log('Store updated with selected key pair');
});
}
};

return (
<GlobalContext.Provider
value={{
values,
setValues,
loginValues,
setLoginValues,
confirmValues,
setConfirmValues,
transactionData,
updateTransaction,
clearData,
loginValues,
setLoginValues,
publicKey,
setPublicKey,
privateKey,
setPrivateKey,
networks,
setNetworks,
keyPairs,
setKeyPairs,
generateKeyPair,
selectedKeyPairIndex,
setSelectedKeyPairIndex,
setSelectedKeyPair,
isAuthenticated,
setIsAuthenticated,
storedPassword,
setStoredPassword,
}}
>
{children}
Expand Down
24 changes: 24 additions & 0 deletions src/css/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -3683,3 +3683,27 @@ tr:hover {
justify-content: flex-end;
}

.keypair-header {
display: flex;
align-items: center;
justify-content: space-between;
}

.keypair-icons {
display: flex;
align-items: center;
}

.icon-button {
background: none;
border: none;
outline: none;
cursor: pointer;
padding: 0 5px;
}

.icon-button:hover {
opacity: 0.7;
}


5 changes: 4 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import reportWebVitals from './reportWebVitals';
import { transitions, positions, Provider as AlertProvider } from 'react-alert';
import AlertTemplate from 'react-alert-template-basic';
import { MemoryRouter } from "react-router-dom";
import { GlobalProvider } from './context/GlobalContext';

// optional configuration
const options = {
Expand All @@ -41,7 +42,9 @@ root.render(
<React.StrictMode>
<MemoryRouter>
<AlertProvider template={AlertTemplate} {...options}>
<App />
<GlobalProvider>
<App />
</GlobalProvider>
</AlertProvider>
</MemoryRouter>
</React.StrictMode>
Expand Down
Loading

0 comments on commit 6c6d3f6

Please sign in to comment.