377 lines
10 KiB
Markdown
377 lines
10 KiB
Markdown
# Implementation Plan: Multi-Keypair Management with Encrypted Spaces
|
|
|
|
## Overview
|
|
|
|
This plan outlines the implementation of a multi-keypair management system with encrypted spaces for the WebAssembly crypto module. The system will allow users to:
|
|
|
|
1. Create and access different "spaces" using different passwords
|
|
2. Manage multiple named keypairs within each space
|
|
3. Select which keypair to use for cryptographic operations
|
|
4. Automatically log out after 15 minutes of inactivity
|
|
|
|
## Architecture
|
|
|
|
```mermaid
|
|
graph TD
|
|
A[User Interface] --> B[WebAssembly API]
|
|
B --> C[Rust Core Implementation]
|
|
C --> D[LocalStorage]
|
|
|
|
subgraph "Frontend (JavaScript)"
|
|
A
|
|
E[Session Management]
|
|
F[UI Components]
|
|
G[Event Handlers]
|
|
end
|
|
|
|
subgraph "WebAssembly Bridge"
|
|
B
|
|
end
|
|
|
|
subgraph "Backend (Rust)"
|
|
C
|
|
H[KeySpace Management]
|
|
I[KeyPair Management]
|
|
J[Encryption/Decryption]
|
|
end
|
|
|
|
E --> A
|
|
F --> A
|
|
G --> A
|
|
H --> C
|
|
I --> C
|
|
J --> C
|
|
```
|
|
|
|
## Data Model
|
|
|
|
```mermaid
|
|
classDiagram
|
|
class KeySpace {
|
|
+String name
|
|
+Map~String, KeyPair~ keypairs
|
|
+encrypt(password)
|
|
+decrypt(password)
|
|
}
|
|
|
|
class KeyPair {
|
|
+String name
|
|
+VerifyingKey publicKey
|
|
+SigningKey privateKey
|
|
+sign(message)
|
|
+verify(message, signature)
|
|
}
|
|
|
|
class LocalStorage {
|
|
+Map~String, EncryptedKeySpace~ spaces
|
|
}
|
|
|
|
class Session {
|
|
+KeySpace currentSpace
|
|
+KeyPair activeKeyPair
|
|
+DateTime lastActivity
|
|
+Boolean isLoggedIn
|
|
}
|
|
|
|
KeySpace "1" --> "*" KeyPair: contains
|
|
LocalStorage "1" --> "*" KeySpace: stores
|
|
Session "1" --> "0..1" KeySpace: references
|
|
Session "1" --> "0..1" KeyPair: references
|
|
```
|
|
|
|
## Implementation Steps
|
|
|
|
### 1. Backend (Rust) Changes
|
|
|
|
#### 1.1 Create New Data Structures
|
|
|
|
- Create a `KeyPair` struct that includes a name and the existing keypair functionality
|
|
- Create a `KeySpace` struct to manage a collection of named keypairs
|
|
- Implement serialization/deserialization for these structures
|
|
|
|
#### 1.2 Update Core Functionality
|
|
|
|
- Remove the global `KEYPAIR` static variable
|
|
- Implement functions to create, retrieve, and manage keypairs by name
|
|
- Implement functions to encrypt/decrypt a `KeySpace` using a password
|
|
- Add error types for the new functionality
|
|
|
|
#### 1.3 Update API Layer
|
|
|
|
- Update the keypair API to work with named keypairs
|
|
- Add functions for:
|
|
- Creating/opening a space with a password
|
|
- Listing available spaces
|
|
- Creating a new keypair in the current space
|
|
- Listing keypairs in the current space
|
|
- Selecting a keypair for operations
|
|
- Signing/verifying with the selected keypair
|
|
|
|
#### 1.4 Update WebAssembly Bindings
|
|
|
|
- Expose the new API functions to JavaScript
|
|
- Ensure proper error handling and type conversions
|
|
|
|
### 2. Frontend (JavaScript/HTML) Changes
|
|
|
|
#### 2.1 Update JavaScript Interface
|
|
|
|
- Create a session management module to track:
|
|
- Current space
|
|
- Selected keypair
|
|
- Login status
|
|
- Last activity timestamp
|
|
- Implement auto-logout after 15 minutes of inactivity
|
|
- Update the existing functions to work with the selected keypair
|
|
|
|
#### 2.2 Update HTML/UI
|
|
|
|
- Add a login section with:
|
|
- Password input
|
|
- Space name input (for creating new spaces)
|
|
- Login/Create buttons
|
|
- Add space management UI:
|
|
- Dropdown to select current space
|
|
- Button to create a new space
|
|
- Add keypair management UI:
|
|
- Dropdown to select current keypair
|
|
- Input for new keypair name
|
|
- Button to create a new keypair
|
|
- Update the existing UI sections to work with the selected keypair
|
|
|
|
## Detailed Technical Approach
|
|
|
|
### Backend Implementation Details
|
|
|
|
1. **KeyPair Structure**:
|
|
```rust
|
|
pub struct KeyPair {
|
|
pub name: String,
|
|
pub verifying_key: VerifyingKey,
|
|
pub signing_key: SigningKey,
|
|
}
|
|
```
|
|
|
|
2. **KeySpace Structure**:
|
|
```rust
|
|
pub struct KeySpace {
|
|
pub name: String,
|
|
pub keypairs: HashMap<String, KeyPair>,
|
|
}
|
|
|
|
impl KeySpace {
|
|
pub fn new(name: &str) -> Self { ... }
|
|
pub fn add_keypair(&mut self, name: &str) -> Result<(), CryptoError> { ... }
|
|
pub fn get_keypair(&self, name: &str) -> Option<&KeyPair> { ... }
|
|
pub fn list_keypairs(&self) -> Vec<String> { ... }
|
|
pub fn encrypt(&self, password: &str) -> Result<Vec<u8>, CryptoError> { ... }
|
|
pub fn decrypt(encrypted: &[u8], password: &str) -> Result<Self, CryptoError> { ... }
|
|
}
|
|
```
|
|
|
|
3. **Session Management**:
|
|
```rust
|
|
pub struct Session {
|
|
pub current_space: Option<KeySpace>,
|
|
pub selected_keypair: Option<String>,
|
|
}
|
|
|
|
static SESSION: OnceCell<Mutex<Session>> = OnceCell::new();
|
|
|
|
pub fn initialize_session() { ... }
|
|
pub fn login(space_name: &str, password: &str) -> Result<(), CryptoError> { ... }
|
|
pub fn create_space(space_name: &str, password: &str) -> Result<(), CryptoError> { ... }
|
|
pub fn logout() { ... }
|
|
pub fn is_logged_in() -> bool { ... }
|
|
```
|
|
|
|
### Frontend Implementation Details
|
|
|
|
1. **Session Management**:
|
|
```javascript
|
|
// Session state
|
|
let currentSpace = null;
|
|
let selectedKeypair = null;
|
|
let lastActivity = Date.now();
|
|
let logoutTimer = null;
|
|
|
|
// Activity tracking
|
|
function updateActivity() {
|
|
lastActivity = Date.now();
|
|
}
|
|
|
|
// Auto-logout
|
|
function setupAutoLogout() {
|
|
logoutTimer = setInterval(() => {
|
|
const inactiveTime = Date.now() - lastActivity;
|
|
if (inactiveTime > 15 * 60 * 1000) { // 15 minutes
|
|
logout();
|
|
}
|
|
}, 60000); // Check every minute
|
|
}
|
|
|
|
// Login/logout functions
|
|
async function login(spaceName, password) { ... }
|
|
async function createSpace(spaceName, password) { ... }
|
|
async function logout() { ... }
|
|
```
|
|
|
|
2. **UI Updates**:
|
|
```javascript
|
|
// Space management
|
|
function updateSpacesList() { ... }
|
|
function selectSpace(spaceName) { ... }
|
|
|
|
// Keypair management
|
|
function updateKeypairsList() { ... }
|
|
function selectKeypair(keypairName) { ... }
|
|
function createKeypair(keypairName) { ... }
|
|
|
|
// Update existing functionality
|
|
function signMessage() {
|
|
// Check if logged in and keypair selected
|
|
if (!selectedKeypair) {
|
|
alert("Please select a keypair first");
|
|
return;
|
|
}
|
|
|
|
// Get message and sign with selected keypair
|
|
const message = document.getElementById('sign-message').value;
|
|
const messageBytes = new TextEncoder().encode(message);
|
|
|
|
try {
|
|
const signature = keypair_sign_with_selected(messageBytes);
|
|
// ...rest of the function
|
|
} catch (e) {
|
|
// ...error handling
|
|
}
|
|
}
|
|
```
|
|
|
|
### LocalStorage Structure
|
|
|
|
The system will use localStorage to persist encrypted key spaces. The structure will be:
|
|
|
|
```javascript
|
|
// localStorage key format: "crypto_space_{spaceName}"
|
|
// localStorage value: JSON string of encrypted space data
|
|
|
|
// Example localStorage entry:
|
|
// Key: "crypto_space_personal"
|
|
// Value: {
|
|
// "name": "personal",
|
|
// "encryptedData": "base64encodedencrypteddata...",
|
|
// "createdAt": "2023-04-19T12:00:00Z",
|
|
// "lastAccessed": "2023-04-19T15:30:00Z"
|
|
// }
|
|
|
|
// Helper functions for localStorage access
|
|
function saveSpaceToStorage(spaceName, encryptedData) {
|
|
const storageKey = `crypto_space_${spaceName}`;
|
|
const storageData = {
|
|
name: spaceName,
|
|
encryptedData: btoa(String.fromCharCode.apply(null, new Uint8Array(encryptedData))),
|
|
createdAt: new Date().toISOString(),
|
|
lastAccessed: new Date().toISOString()
|
|
};
|
|
localStorage.setItem(storageKey, JSON.stringify(storageData));
|
|
}
|
|
|
|
function getSpaceFromStorage(spaceName) {
|
|
const storageKey = `crypto_space_${spaceName}`;
|
|
const storageData = JSON.parse(localStorage.getItem(storageKey));
|
|
if (!storageData) return null;
|
|
|
|
// Update last accessed time
|
|
storageData.lastAccessed = new Date().toISOString();
|
|
localStorage.setItem(storageKey, JSON.stringify(storageData));
|
|
|
|
// Return the encrypted data as Uint8Array
|
|
return new Uint8Array(
|
|
atob(storageData.encryptedData)
|
|
.split('')
|
|
.map(c => c.charCodeAt(0))
|
|
);
|
|
}
|
|
|
|
function listSpacesFromStorage() {
|
|
const spaces = [];
|
|
for (let i = 0; i < localStorage.length; i++) {
|
|
const key = localStorage.key(i);
|
|
if (key.startsWith('crypto_space_')) {
|
|
const spaceName = key.substring('crypto_space_'.length);
|
|
spaces.push(spaceName);
|
|
}
|
|
}
|
|
return spaces;
|
|
}
|
|
|
|
function removeSpaceFromStorage(spaceName) {
|
|
const storageKey = `crypto_space_${spaceName}`;
|
|
localStorage.removeItem(storageKey);
|
|
}
|
|
```
|
|
|
|
## UI Mockup
|
|
|
|
```
|
|
+------------------------------------------+
|
|
| Rust WebAssembly Crypto Example |
|
|
+------------------------------------------+
|
|
|
|
+------------------------------------------+
|
|
| Space Management |
|
|
| |
|
|
| Password: [________] Space: [________] |
|
|
| |
|
|
| [Login] [Create Space] [Logout] |
|
|
| |
|
|
| Current Space: [Dropdown▼] |
|
|
+------------------------------------------+
|
|
|
|
+------------------------------------------+
|
|
| Keypair Management |
|
|
| |
|
|
| Keypair Name: [________] |
|
|
| |
|
|
| [Create Keypair] |
|
|
| |
|
|
| Selected Keypair: [Dropdown▼] |
|
|
+------------------------------------------+
|
|
|
|
... (existing UI sections, updated to work with
|
|
the selected keypair) ...
|
|
```
|
|
|
|
## Testing Strategy
|
|
|
|
1. **Unit Tests**:
|
|
- Test KeyPair and KeySpace functionality
|
|
- Test encryption/decryption of spaces
|
|
- Test session management
|
|
|
|
2. **Integration Tests**:
|
|
- Test the full flow from login to using keypairs
|
|
- Test auto-logout functionality
|
|
- Test persistence to localStorage
|
|
|
|
3. **UI Testing**:
|
|
- Test the UI components for managing spaces and keypairs
|
|
- Test error handling and user feedback
|
|
|
|
## Implementation Timeline
|
|
|
|
1. **Phase 1: Backend Implementation**
|
|
- Implement the core data structures and functionality
|
|
- Update the API layer
|
|
- Update the WebAssembly bindings
|
|
|
|
2. **Phase 2: Frontend Implementation**
|
|
- Implement session management
|
|
- Update the UI for space and keypair management
|
|
- Update the existing functionality to work with selected keypairs
|
|
|
|
3. **Phase 3: Testing and Refinement**
|
|
- Test the implementation
|
|
- Fix any issues
|
|
- Refine the UI based on feedback |