remove files, update README

This commit is contained in:
Loïc Gremaud 2025-10-21 14:33:14 +02:00
parent d8cf61be47
commit 5ab7004477
Signed by: Legrems
GPG Key ID: D4620E6DF3E0121D
18 changed files with 30 additions and 3835 deletions

View File

@ -1 +0,0 @@
3.13

View File

@ -1,97 +0,0 @@
# Changelog
All notable changes to Browser Vault GUI will be documented in this file.
## [0.2.0] - 2024-01-XX - Vue 3 Migration + Credential Saving
### ✨ Major Changes
#### Vue 3 Migration
- **BREAKING**: Complete rewrite from React to Vue 3
- Replaced React with Vue 3 Composition API
- Replaced custom CSS with Tailwind CSS
- Added DaisyUI for beautiful UI components
- ~30% smaller bundle size
- Better performance and developer experience
#### New Feature: Optional Credential Saving
- Added option to save credentials in localStorage (opt-in)
- Prominent security warning modal on first save
- Visual indicators (🔓 badge) for servers with saved credentials
- Auto-fill credentials on subsequent logins
- Easy removal of saved credentials
- **Security**: Disabled by default, requires explicit user consent
### 📦 Added
- Vue 3 with `<script setup>` syntax
- Tailwind CSS for utility-first styling
- DaisyUI component library
- Credential saving feature (with warnings)
- Security warning modal
- `SECURITY_CREDENTIALS.md` documentation
- `VUE_MIGRATION.md` migration guide
- Server badges showing saved credential status
### 🔄 Changed
- All `.tsx` components converted to `.vue`
- All custom CSS replaced with Tailwind utilities
- Form inputs now use DaisyUI components
- Improved responsive design
- Better dark/light mode support
- Enhanced warning colors for security features
### 🗑️ Removed
- All React dependencies
- All `.tsx` files
- All custom `.css` component files
- React-specific ESLint config
### ⚠️ Security Notes
- Credential saving is **opt-in only**
- Multiple security warnings shown to users
- Plain text storage with clear disclosure
- Recommended only for development/testing
- See `SECURITY_CREDENTIALS.md` for full analysis
### 🐛 Fixed
- Mount point checkbox selectability issue
- API response parsing for `/v1/sys/internal/ui/mounts`
- TypeScript strict mode compatibility
---
## [0.1.0] - 2024-01-XX - Initial React Release
### ✨ Initial Features
- Multiple Vault server management
- Token, Userpass, and LDAP authentication
- Login verification with mount point detection
- Automatic KV v1/v2 detection
- Secret reading and browsing
- Recursive path search
- Multi-mount point search
- Smart caching system
- Settings panel for cache and search configuration
- KV Secret Engine v1 and v2 support
- Browser-compatible Vault HTTP client
- Retry and timeout handling
- Comprehensive error messages
- CORS configuration guidance
- React 18 + TypeScript
- Vite build tooling
- Modern CSS3 styling
### 📚 Documentation
- `README.md` - Project overview and setup
- `KV_VERSIONS.md` - KV v1 vs v2 guide
- `MOUNT_POINTS.md` - Mount point detection
- `CORS_AND_CLIENT.md` - CORS configuration
- `LATEST_FEATURES.md` - Recent features
- `IMPROVEMENTS_SUMMARY.md` - Architecture notes
---
## Version History
- **0.2.0** - Vue 3 migration + credential saving (current)
- **0.1.0** - Initial React implementation

View File

@ -1,240 +0,0 @@
# Cleanup & Security Improvements Summary
## ✅ All Requested Changes Implemented
### 1. 🔒 Secrets Never Cached (Security Fix)
**Problem**: Secret data was being cached in localStorage, which is a security risk.
**Solution**:
- ✅ Removed all caching from `readSecret()` method
- ✅ Secret data is now **always fetched fresh** from Vault
- ✅ Only directory listings are cached (for search performance)
- ✅ Updated UI to clearly indicate this security improvement
**Code Changes**:
```typescript
// Before: Cached secret data
async readSecret() {
const cached = vaultCache.get(cacheKey);
if (cached) return cached; // ❌ Security risk
const data = await client.read(path);
vaultCache.set(cacheKey, data); // ❌ Caching secrets
return data;
}
// After: Never cache secrets
async readSecret() {
console.log(`⚡ API call for read (no cache): ${path}`);
const data = await client.read(path);
// SECURITY: Never cache secret data - always fetch fresh
return data;
}
```
### 2. 🎯 Mount Point Selector (UX Improvement)
**Problem**: Users had to manually type full paths including mount points.
**Solution**:
- ✅ Added dropdown selector for available mount points
- ✅ Separate input field for the secret path (without mount prefix)
- ✅ Visual preview of the full path being constructed
- ✅ Auto-parsing when selecting paths from search results
**UI Changes**:
```
Before: [secret/data/myapp/config ] [Read Secret]
After: Mount Point: [secret ▼] (kv v2)
Secret Path: [secret/] [data/myapp/config] [Read Secret]
Full path: secret/data/myapp/config
```
**Features**:
- Mount point dropdown shows: `secret/ (kv v2)`, `kv/ (kv v2)`, etc.
- Path input is disabled until mount point is selected
- Button is disabled until both mount point and path are provided
- Search results auto-populate the correct mount point + path
### 3. 🔍 Search Shown by Default
**Problem**: Search was hidden by default, but it's the primary function.
**Solution**:
- ✅ Changed `showSearch = ref(true)` (was `false`)
- ✅ Search component is now visible immediately upon login
- ✅ Button text updated to "Hide Search" / "Show Search"
### 4. 🌐 Search All Mount Points by Default
**Problem**: "Search across all mount points" was disabled by default.
**Solution**:
- ✅ Changed `searchAllMounts = ref(true)` (was `false`)
- ✅ Multi-mount search is now enabled by default
- ✅ Users can still disable it if they want to search a specific mount
## Security Improvements
### 🔒 Secret Data Protection
- **Never cached**: Secret values are always fetched fresh
- **Memory only**: Secret data exists only in component state during viewing
- **No persistence**: Secrets are not stored in localStorage
- **Clear indicators**: UI explicitly states "Secret data is never cached"
### 📂 Directory Listing Caching (Still Enabled)
- **Performance**: Directory listings are still cached for search speed
- **No sensitive data**: Only path names, not secret values
- **Configurable**: Cache can be cleared manually
- **Reasonable**: Directory structure is less sensitive than secret values
## User Experience Improvements
### 🎯 Better Path Input
- **Guided input**: Mount point dropdown prevents typos
- **Visual feedback**: Shows full path being constructed
- **Auto-completion**: Search results populate the form correctly
- **Validation**: Button disabled until valid input provided
### 🔍 Search-First Interface
- **Primary function**: Search is now the main interface
- **Immediate access**: No need to click "Show Search"
- **Multi-mount default**: Searches all available secret engines
- **Comprehensive**: Finds secrets across the entire Vault instance
### 📱 Responsive Design
- **Mount point selector**: Works well on mobile
- **Path preview**: Clear indication of what will be accessed
- **Disabled states**: Clear visual feedback for invalid states
## Technical Implementation
### Cache Logic Changes
```typescript
// Only directory listings cached now
async listSecrets(path: string) {
const cached = vaultCache.get(cacheKey);
if (cached) return cached; // ✅ OK - just directory names
const listing = await client.list(path);
vaultCache.set(cacheKey, listing); // ✅ OK - no secret values
return listing;
}
// Secret data never cached
async readSecret(path: string) {
// No cache check - always fetch fresh
return await client.read(path); // ✅ Always fresh data
}
```
### Mount Point Integration
```typescript
// Parse search results to extract mount + path
const handleSelectPath = (fullPath: string) => {
const mountPoints = connection.mountPoints || []
// Find matching mount point
for (const mount of mountPoints) {
if (fullPath.startsWith(mount.path + '/')) {
selectedMountPoint.value = mount.path
secretPath.value = fullPath.substring(mount.path.length + 1)
break
}
}
handleReadSecret(fullPath)
}
```
## Configuration Updates
### Default Settings
- **Search visible**: `showSearch = true`
- **Multi-mount search**: `searchAllMounts = true`
- **No secret caching**: Removed from `readSecret()`
- **Directory caching**: Still enabled for performance
### User Control
- Users can still hide search if desired
- Users can disable multi-mount search for specific searches
- Cache settings still configurable in Settings panel
- Mount point selection is per-operation
## Documentation Updates
### README.md
- Updated cache security section
- Clarified what is/isn't cached
- Emphasized secret data protection
### UI Messages
- "Secret data is never cached - always fetched fresh"
- "Directory listings are cached to improve search performance"
- Clear security indicators throughout interface
## Benefits
### 🔒 Security
- **Zero secret persistence**: Secrets never touch localStorage
- **Fresh data guarantee**: Always get current secret values
- **Reduced attack surface**: No cached secrets to compromise
### 🚀 Performance
- **Smart caching**: Directory listings cached for search speed
- **Reduced API calls**: Search still benefits from caching
- **Responsive UI**: Mount point selector is fast and intuitive
### 👥 User Experience
- **Search-first**: Primary function is immediately available
- **Guided input**: Mount point selector prevents errors
- **Multi-mount default**: Comprehensive search out of the box
- **Clear feedback**: Visual indicators for all states
## Migration Notes
### For Existing Users
- **No data loss**: Existing server configurations preserved
- **Better security**: Secret data no longer cached (automatic improvement)
- **New UI**: Mount point selector may require brief learning
- **Search default**: Search is now shown by default (can be hidden)
### For Developers
- **API unchanged**: `vaultApi.readSecret()` still works the same
- **Caching removed**: No more secret data in cache
- **UI components**: New mount point selector component
- **Default states**: Search and multi-mount enabled by default
## Testing Recommendations
1. **Verify no secret caching**:
- Read a secret
- Check localStorage - should contain no secret values
- Only directory listings should be cached
2. **Test mount point selector**:
- Select different mount points
- Verify path construction
- Test with search result selection
3. **Confirm search defaults**:
- Login to Vault
- Search should be visible immediately
- "Search all mount points" should be checked
4. **Security validation**:
- Read multiple secrets
- Confirm fresh API calls each time
- Verify no secret data in browser storage
## Conclusion
**All requested changes implemented successfully**:
- 🔒 Secrets never cached (security improvement)
- 🎯 Mount point selector (UX improvement)
- 🔍 Search shown by default (primary function)
- 🌐 Multi-mount search by default (comprehensive)
The application is now more secure, more user-friendly, and better aligned with its primary purpose as a Vault search and browsing tool.

View File

@ -1,356 +0,0 @@
# CORS and Vault Client Implementation
## ❌ Why Your Changes Won't Work
You tried to fix CORS by adding these changes:
```typescript
// ❌ This won't work
headers: {
'Access-Control-Allow-Origin': '*'
}
// ❌ This will break response reading
mode: 'no-cors'
```
### Why `Access-Control-Allow-Origin` in Client Headers Doesn't Work
**CORS headers MUST be set by the SERVER, not the client.**
When you add `Access-Control-Allow-Origin: *` to your request headers:
1. The header is sent to the server
2. The server ignores it (only the server's response headers matter)
3. The browser still blocks the response because the server didn't send the CORS header
**How CORS Actually Works:**
```
Browser → Request to vault.example.com
Vault Server → Response with header: Access-Control-Allow-Origin: https://yourfrontend.com
Browser → Allows JavaScript to read the response
```
### Why `mode: 'no-cors'` Breaks Everything
The `no-cors` mode:
- ✅ Allows the request to be sent
- ❌ **Prevents you from reading the response body**
- ❌ You can't access status codes
- ❌ You can't read JSON data
- ❌ You only get an "opaque" response
It's called "no-cors" mode because it **doesn't check CORS**, but it also **doesn't let you use the response**.
**Example:**
```typescript
// With no-cors
const response = await fetch(url, { mode: 'no-cors' });
console.log(response.status); // Always 0
console.log(await response.json()); // Error: Can't read body
```
## ✅ The Proper Solution
### 1. Configure Your Vault Server
Add CORS configuration to your Vault server config file:
```hcl
# vault.hcl
ui = true
listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = 1 # Only for development! Use TLS in production
# Enable CORS
cors_enabled = true
cors_allowed_origins = [
"http://localhost:5173", # Vite dev server
"https://yourdomain.com" # Production domain
]
cors_allowed_headers = ["*"]
}
```
Or if using Docker:
```yaml
# docker-compose.yml
version: '3.8'
services:
vault:
image: vault:latest
ports:
- "8200:8200"
environment:
VAULT_DEV_ROOT_TOKEN_ID: myroot
VAULT_DEV_LISTEN_ADDRESS: 0.0.0.0:8200
VAULT_API_ADDR: http://127.0.0.1:8200
cap_add:
- IPC_LOCK
command:
- server
- -dev
- -dev-root-token-id=myroot
```
Then exec into the container and configure CORS via the API:
```bash
docker exec -it vault sh
vault write sys/config/cors enabled=true allowed_origins="http://localhost:5173"
```
### 2. Use the Proper Vault Client
We've now implemented a proper browser-compatible Vault client:
```typescript
// ✅ NEW: Clean, maintainable VaultClient
import { VaultClient } from './services/vaultClient';
const client = new VaultClient({
server: { url: 'https://vault.example.com', ... },
credentials: { token: 'your-token', ... },
timeout: 30000,
retries: 2
});
// Read a secret
const data = await client.read('secret/data/myapp/config');
// List secrets
const keys = await client.list('secret/');
// Write a secret
await client.write('secret/data/myapp/config', {
username: 'admin',
password: 'secret'
});
// Delete a secret
await client.delete('secret/data/myapp/config');
```
## 🏗️ Architecture: Why Use a Client Class?
### Before (Raw API Calls)
```typescript
// ❌ Hard to maintain, error-prone
async function readSecret(url, token, path) {
const response = await fetch(`${url}/v1/${path}`, {
headers: {
'X-Vault-Token': token,
'Content-Type': 'application/json'
}
});
if (!response.ok) {
throw new Error('Failed'); // Not helpful
}
const data = await response.json();
return data.data.data; // Confusing nested structure
}
```
### After (VaultClient)
```typescript
// ✅ Clean, maintainable, type-safe
const client = new VaultClient(options);
const data = await client.read(path); // Simple!
```
### Benefits of VaultClient
1. **Error Handling**
```typescript
try {
await client.read('secret/data/test');
} catch (error) {
if (error instanceof VaultError) {
console.log(error.statusCode); // 403
console.log(error.errors); // ["permission denied"]
}
}
```
2. **Automatic Retries**
- Retries on network errors
- Exponential backoff
- Configurable retry count
3. **Timeout Protection**
```typescript
const client = new VaultClient({
...options,
timeout: 5000 // 5 seconds
});
// Request will abort after 5 seconds
```
4. **Path Normalization**
```typescript
// All of these work the same:
await client.read('/secret/data/test');
await client.read('secret/data/test');
await client.read('//secret/data/test//');
// All normalized to: secret/data/test
```
5. **Authentication Methods**
```typescript
// Token (already have one)
const client = new VaultClient({
server,
credentials: { token: 'your-token', ... }
});
// Username/Password (get token)
const token = await client.loginUserpass('username', 'password');
// LDAP (get token)
const token = await client.loginLdap('username', 'password');
```
6. **Type Safety**
```typescript
// TypeScript knows the structure
interface MySecret {
username: string;
password: string;
}
const data = await client.read<MySecret>('secret/data/myapp');
console.log(data.username); // TypeScript autocomplete works!
```
## 🔧 Testing Your CORS Configuration
### 1. Test with curl (should work)
```bash
curl -X GET \
-H "X-Vault-Token: your-token" \
http://localhost:8200/v1/secret/data/test
```
### 2. Test from browser console
```javascript
fetch('http://localhost:8200/v1/secret/data/test', {
headers: {
'X-Vault-Token': 'your-token'
}
})
.then(r => r.json())
.then(console.log)
.catch(console.error);
```
If you see a CORS error here, your Vault server CORS is not configured correctly.
### 3. Check Response Headers
In browser DevTools → Network tab, check the response headers:
```
✅ Should see:
Access-Control-Allow-Origin: http://localhost:5173
Access-Control-Allow-Headers: *
❌ If missing:
Your Vault server CORS is not configured
```
## 🆚 Comparison: Raw API vs VaultClient
| Feature | Raw fetch() | VaultClient |
|---------|-------------|-------------|
| Code lines (typical read) | ~15 lines | 1 line |
| Error handling | Manual | Built-in |
| Retries | Manual | Automatic |
| Timeouts | Manual | Built-in |
| Type safety | None | Full |
| Path normalization | Manual | Automatic |
| Authentication | Manual | Built-in |
| Token management | Manual | Built-in |
| Health checks | Manual | Built-in |
| Maintainability | Low | High |
## 📚 Advanced Usage
### Custom Error Handling
```typescript
import { VaultError } from './services/vaultClient';
try {
const data = await client.read('secret/data/test');
} catch (error) {
if (error instanceof VaultError) {
switch (error.statusCode) {
case 403:
alert('Permission denied');
break;
case 404:
alert('Secret not found');
break;
case 500:
alert('Vault server error');
break;
default:
alert(error.message);
}
}
}
```
### Health Check Before Operations
```typescript
const client = new VaultClient(options);
// Check if Vault is healthy
const health = await client.health();
if (health.sealed) {
alert('Vault is sealed! Please unseal it first.');
return;
}
// Now safe to perform operations
const data = await client.read('secret/data/test');
```
### Token Lifecycle Management
```typescript
// Login
const client = new VaultClient(options);
const token = await client.loginUserpass('user', 'pass');
// Check token info
const tokenInfo = await client.tokenLookupSelf();
console.log('Token expires:', tokenInfo.data.expire_time);
console.log('Token TTL:', tokenInfo.data.ttl);
// Revoke token on logout
await client.tokenRevokeSelf();
```
## 🎯 Summary
1. **CORS must be configured on the Vault SERVER, not the client**
2. **`mode: 'no-cors'` prevents you from reading responses**
3. **Use the VaultClient class for clean, maintainable code**
4. **VaultClient provides:**
- Automatic retries
- Timeout protection
- Better error messages
- Type safety
- Built-in authentication
- Path normalization
The new implementation is production-ready, maintainable, and properly handles all edge cases!

View File

@ -1,237 +0,0 @@
# Feature Summary
## ✅ Completed Features
### 1. Recursive Path Search 🔍
- **Location**: Dashboard → "🔍 Search" button
- **Functionality**:
- Recursively searches through vault paths
- Configurable search depth to prevent infinite loops
- Configurable maximum results
- Case-insensitive partial matching
- Distinguishes between directories (📁) and secrets (📄)
- **Performance**:
- Search time displayed
- Results cached automatically
- Non-blocking UI during search
### 2. Smart Caching System 💾
- **Location**: Implemented globally, managed in Settings
- **Features**:
- Caches all API responses (list and read operations)
- Configurable cache size limit (MB)
- Configurable expiration time (minutes)
- Automatic size enforcement with LRU eviction
- Cache key format: `{serverId}:{operation}:{path}`
- **Statistics**:
- Real-time cache size monitoring
- Entry count tracking
- Oldest/newest entry timestamps
- Manual cache clearing
### 3. Configuration System ⚙️
- **Location**: Dashboard → "⚙️ Settings" button
- **Cache Configuration**:
- Enable/disable caching
- Max cache size (1-100 MB, default: 10 MB)
- Cache expiration (1-1440 minutes, default: 30 min)
- **Search Configuration**:
- Max search depth (1-50, default: 10)
- Max search results (10-10000, default: 1000)
- **Persistence**: All settings saved to localStorage
### 4. Vault API Client 🔌
- **Location**: `src/services/vaultApi.ts`
- **Implemented Endpoints**:
- ✅ `listSecrets()` - LIST endpoint with caching
- ✅ `readSecret()` - GET endpoint with caching
- ✅ `searchPaths()` - Recursive search with depth control
- **Features**:
- Automatic cache integration
- Error handling
- Path normalization
- Support for multiple auth methods
### 5. Cache Manager 🗄️
- **Location**: `src/utils/cache.ts`
- **Capabilities**:
- localStorage-based persistence
- Size calculation and enforcement
- Age-based expiration
- LRU eviction when quota exceeded
- Cleanup of expired entries
- Statistics collection
- **Methods**:
- `get<T>(key)` - Retrieve with expiration check
- `set<T>(key, data)` - Store with size calculation
- `has(key)` - Check existence
- `delete(key)` - Remove entry
- `clear()` - Remove all entries
- `getStats()` - Get cache statistics
- `cleanup()` - Remove expired entries
### 6. Settings UI 🎛️
- **Location**: `src/components/Settings.tsx`
- **Features**:
- Modal overlay interface
- Real-time cache statistics
- Form validation
- Immediate save and apply
- Responsive design
### 7. Search UI 🔎
- **Location**: `src/components/PathSearch.tsx`
- **Features**:
- Base path configuration
- Search term input with Enter key support
- Loading spinner during search
- Search statistics (results count, time taken)
- Clickable results for secrets
- Visual distinction of directories vs secrets
- Depth indicator for each result
- Helpful search tips
## 🎨 UI/UX Enhancements
### Dashboard Updates
- Added action button group (Search, Settings, Logout)
- Toggle search panel visibility
- Integrated settings modal
- Improved responsive layout
### Visual Feedback
- Loading states for all async operations
- Progress indicators during search
- Success/error messages
- Cache statistics display
- Search result highlighting
## 🔒 Security Features
### Data Protection
- ✅ Credentials never cached or persisted
- ✅ Only in-memory storage during session
- ✅ Server configurations saved securely
- ✅ Cache can be manually cleared
- ⚠️ Cached data includes secret values (cleared on logout recommended)
### DDoS Prevention
- ✅ Configurable cache prevents repeat API calls
- ✅ Search depth limits prevent runaway recursion
- ✅ Result limits prevent memory exhaustion
- ✅ Automatic size enforcement prevents quota issues
## 📊 Performance Optimizations
### Caching Strategy
1. **Cache Hit**: Instant response from localStorage
2. **Cache Miss**: API call + cache storage
3. **Cache Expiration**: Automatic refresh after configured time
4. **Cache Eviction**: LRU algorithm when size limit reached
### Search Optimization
1. **Early Exit**: Stops at max results or depth
2. **Parallel Operations**: Could be enhanced with Promise.all
3. **Progress Feedback**: Non-blocking UI
4. **Cached Paths**: Subsequent searches of same paths are instant
## 📁 File Structure
```
src/
├── components/
│ ├── ServerSelector.tsx/css # Multi-server management
│ ├── LoginForm.tsx/css # Authentication UI
│ ├── Dashboard.tsx/css # Main dashboard (enhanced)
│ ├── PathSearch.tsx/css # NEW: Search interface
│ └── Settings.tsx/css # NEW: Settings modal
├── services/
│ └── vaultApi.ts # NEW: API client with caching
├── utils/
│ └── cache.ts # NEW: Cache management
├── config.ts # NEW: Configuration system
├── types.ts # Type definitions
├── App.tsx/css # Main app
├── main.tsx # Entry point
└── index.css # Global styles
```
## 🧪 Testing Recommendations
### Manual Testing Checklist
- [ ] Add/remove vault servers
- [ ] Connect with token auth
- [ ] Read a secret directly
- [ ] Perform recursive search
- [ ] Verify cache hit (check console logs)
- [ ] Adjust cache settings
- [ ] Clear cache
- [ ] View cache statistics
- [ ] Test search depth limits
- [ ] Test result limits
- [ ] Test with expired cache
- [ ] Test with full localStorage
- [ ] Test responsive design
- [ ] Test logout (clears session but not cache)
### Edge Cases to Test
- [ ] Search with no results
- [ ] Search at max depth
- [ ] Search at max results
- [ ] Very large cache size
- [ ] Very small cache size
- [ ] Cache expiration edge cases
- [ ] localStorage quota exceeded
- [ ] CORS errors
- [ ] Network errors
- [ ] Invalid paths
- [ ] Invalid credentials
## 🔮 Future Enhancements
### Potential Additions
1. **Auto-clear cache on logout** (currently requires manual clear)
2. **Cache encryption** for sensitive data
3. **Parallel search** with Promise.all for better performance
4. **Search filters** (directories only, secrets only, etc.)
5. **Search history** saved in localStorage
6. **Export/import settings**
7. **Secret writing/updating**
8. **Secret deletion**
9. **Batch operations**
10. **Tree view** for path browsing
### Code Improvements
1. Add unit tests for cache manager
2. Add integration tests for API client
3. Add E2E tests with Playwright
4. Implement proper error boundaries
5. Add telemetry/analytics (opt-in)
6. Improve TypeScript strictness
7. Add API request cancellation
8. Implement retry logic
9. Add request queuing/throttling
10. Add offline support
## 📖 Documentation
- ✅ `README.md` - Updated with new features
- ✅ `USAGE.md` - Comprehensive usage guide
- ✅ `FEATURES.md` - This file
- ✅ Inline code comments
- ✅ JSDoc comments on key functions
- ✅ Configuration examples
## 🎯 Key Accomplishments
1. ✅ **Recursive search** with configurable limits
2. ✅ **Smart caching** to prevent DDoS
3. ✅ **Configurable settings** for both cache and search
4. ✅ **Real-time statistics** for monitoring
5. ✅ **Clean architecture** with separation of concerns
6. ✅ **Type safety** throughout
7. ✅ **Responsive UI** that works on mobile
8. ✅ **Production-ready** with proper error handling
9. ✅ **Well-documented** with multiple documentation files
10. ✅ **Extensible** design for future enhancements

View File

@ -1,272 +0,0 @@
# Final UI/UX Improvements Summary
## ✅ All Requested Changes Implemented
### 1. 🎯 First Mount Point Selected by Default
**Problem**: Users had to manually select a mount point every time.
**Solution**:
- ✅ Added `onMounted()` hook in Dashboard
- ✅ Automatically selects first available mount point
- ✅ Immediate usability - no extra clicks needed
**Code**:
```typescript
onMounted(() => {
if (props.connection.mountPoints && props.connection.mountPoints.length > 0) {
selectedMountPoint.value = props.connection.mountPoints[0].path
}
})
```
### 2. 🌐 Always Search All Mount Points (Removed Toggle)
**Problem**: Toggle was confusing and the default should be comprehensive search.
**Solution**:
- ✅ Removed checkbox toggle from PathSearch
- ✅ Always searches across all mount points
- ✅ Simplified UI with clear info message
- ✅ Updated search tips and messaging
**Changes**:
- Removed `searchAllMounts` reactive variable
- Always calls `vaultApi.searchAllMounts()`
- Replaced checkbox with informational alert
- Updated all UI text to reflect always-on behavior
### 3. 📋 Secret Viewer Modal with Metadata & History
**Problem**: Secrets were displayed inline, no metadata or version history.
**Solution**:
- ✅ Created comprehensive `SecretModal.vue` component
- ✅ Tabbed interface: Current Data | Metadata | Versions
- ✅ Full metadata display for KV v2 secrets
- ✅ Version history with ability to view specific versions
- ✅ Copy to clipboard functionality
- ✅ Responsive design with proper overflow handling
**Features**:
#### 📄 Current Data Tab
- JSON formatted secret data
- Copy to clipboard button
- Syntax highlighting
- Scrollable for large secrets
#### 📋 Metadata Tab (KV v2 only)
- General info: current version, max versions, created/updated times
- Status: destroyed flag, deletion policies
- Custom metadata if present
- Raw metadata JSON view
#### 🕒 Versions Tab (KV v2 only)
- Complete version history
- Version status (current, destroyed)
- Creation and deletion timestamps
- "View Version" buttons to load specific versions
- Sorted by version (latest first)
#### 🔒 Security Features
- Always fetches fresh data (no caching)
- Clear indicators about security practices
- KV version awareness (v1 vs v2 features)
## Technical Implementation Details
### SecretModal Component Structure
```vue
<template>
<div class="modal modal-open">
<div class="modal-box max-w-6xl max-h-[90vh]">
<!-- Header with path and close button -->
<!-- Loading/Error states -->
<!-- Tabbed content -->
<div class="tabs tabs-bordered">
<button class="tab">📄 Current Data</button>
<button class="tab">📋 Metadata</button>
<button class="tab">🕒 Versions</button>
</div>
<!-- Tab content with proper overflow handling -->
<!-- Footer with security info -->
</div>
</div>
</template>
```
### API Integration
**Secret Data Loading**:
```typescript
const loadSecret = async () => {
// Load current secret data (always fresh)
const data = await vaultApi.readSecret(server, credentials, secretPath)
// Load metadata and versions for KV v2
if (server.kvVersion === 2) {
await loadMetadataAndVersions()
}
}
```
**Version Loading**:
```typescript
const loadVersion = async (version: number) => {
// Load specific version with ?version=X parameter
const versionPath = `${secretPath}?version=${version}`
const data = await vaultApi.readSecret(server, credentials, versionPath)
}
```
### Dashboard Integration
**Modal Trigger**:
```typescript
const handleSelectPath = (path: string) => {
// Parse path to update form fields
// Open modal instead of inline display
selectedSecretPath.value = path
showSecretModal.value = true
}
const handleViewSecret = () => {
// Build path from mount point + secret path
const fullPath = `${selectedMountPoint.value}/${secretPath.value}`
selectedSecretPath.value = fullPath
showSecretModal.value = true
}
```
## User Experience Improvements
### 🎯 Streamlined Workflow
1. **Login** → First mount point auto-selected
2. **Search** → Always comprehensive across all mounts
3. **View Secret** → Rich modal with all metadata
4. **Browse Versions** → Full history for KV v2
### 🔍 Enhanced Search Experience
- **No configuration needed** - always searches everything
- **Clear feedback** - shows which mount points are being searched
- **Simplified UI** - removed confusing toggle
- **Better results** - mount point shown for each result
### 📱 Better Mobile Experience
- **Large modal** - max-w-6xl for desktop, responsive on mobile
- **Scrollable content** - proper overflow handling
- **Touch-friendly** - large buttons and touch targets
- **Readable text** - appropriate font sizes
### 🔒 Security Transparency
- **Clear indicators** - "Secret data is never cached"
- **Fresh data guarantee** - always fetched from Vault
- **Version awareness** - shows KV v1 vs v2 capabilities
- **Metadata visibility** - full transparency into secret lifecycle
## Performance Optimizations
### 🚀 Smart Loading
- **Lazy metadata loading** - only for KV v2 secrets
- **On-demand versions** - loaded when tab is accessed
- **Efficient API calls** - minimal requests for maximum data
- **Error handling** - graceful degradation for missing features
### 💾 Intelligent Caching
- **Directory listings** - cached for search performance
- **Secret data** - never cached (security)
- **Metadata** - not cached (always fresh)
- **Mount points** - cached during session
## Accessibility Improvements
### ♿ Better Navigation
- **Keyboard support** - Enter key works in forms
- **Focus management** - proper tab order
- **Screen reader friendly** - semantic HTML
- **Clear labels** - descriptive text throughout
### 🎨 Visual Design
- **Consistent icons** - 📄 for secrets, 📁 for directories
- **Status indicators** - badges for versions, mount points
- **Color coding** - success/error/warning states
- **Responsive layout** - works on all screen sizes
## Migration Notes
### For Existing Users
- **No breaking changes** - all existing functionality preserved
- **Better defaults** - first mount point selected automatically
- **Enhanced features** - modal provides much more information
- **Simplified interface** - removed confusing search toggle
### For Developers
- **New component** - `SecretModal.vue` added
- **Updated Dashboard** - modal integration
- **Simplified PathSearch** - removed toggle complexity
- **Enhanced API usage** - better metadata handling
## Testing Recommendations
### 🧪 Functional Testing
1. **Mount point selection** - verify first mount auto-selected
2. **Search behavior** - confirm always searches all mounts
3. **Modal functionality** - test all tabs and features
4. **Version loading** - test KV v2 version history
5. **Error handling** - test with invalid paths/permissions
### 🔒 Security Testing
1. **No secret caching** - verify localStorage contains no secrets
2. **Fresh data** - confirm API calls for each secret view
3. **Metadata security** - ensure metadata doesn't leak sensitive info
4. **Version access** - test permission handling for versions
### 📱 UI/UX Testing
1. **Responsive design** - test on mobile/tablet/desktop
2. **Modal behavior** - test scrolling, overflow, closing
3. **Keyboard navigation** - test all interactions
4. **Loading states** - verify proper feedback during API calls
## Benefits Summary
### 🎯 User Experience
- **Faster workflow** - auto-selected mount point
- **Comprehensive search** - always finds everything
- **Rich secret viewing** - metadata and version history
- **Better mobile support** - responsive modal design
### 🔒 Security
- **No secret caching** - always fresh data
- **Clear transparency** - users know what's cached
- **Version control** - full audit trail for KV v2
- **Metadata visibility** - complete secret lifecycle
### 🚀 Performance
- **Smart caching** - directories cached, secrets fresh
- **Efficient loading** - lazy load metadata/versions
- **Responsive UI** - no blocking operations
- **Optimized API calls** - minimal requests
### 👥 Developer Experience
- **Clean architecture** - well-separated concerns
- **Reusable components** - modal can be extended
- **Type safety** - full TypeScript coverage
- **Maintainable code** - clear separation of logic
## Conclusion
**All requested improvements implemented successfully**:
1. **🎯 First mount point selected by default** - Immediate usability
2. **🌐 Always search all mount points** - Comprehensive by default
3. **📋 Rich secret modal** - Metadata, versions, and better UX
The application now provides a **streamlined, comprehensive, and secure** experience for browsing Vault secrets with **professional-grade** metadata visibility and **mobile-friendly** design.
**Key Achievement**: Transformed from a basic secret reader into a **full-featured Vault browser** with enterprise-level capabilities while maintaining simplicity and security.

View File

@ -1,203 +0,0 @@
# Improvements Summary
## ✅ Your Feedback Implemented
### 1. "You should probably use a vault-client instead of the raw api, no?"
**✅ DONE**: Created proper `VaultClient` class
- Browser-compatible Vault HTTP API client
- Automatic retries with exponential backoff
- Timeout protection
- Type-safe operations
- Better error handling with `VaultError` class
- See: `src/services/vaultClient.ts`
### 2. "You should make the call on /secret/metadata instead no?"
**✅ DONE**: Proper KV v1/v2 support with correct paths
- **KV v2 LIST operations** now use `/metadata/` endpoint (correct!)
- **KV v2 READ/WRITE** operations use `/data/` endpoint
- **KV v1** uses direct paths (no prefixes)
- Automatic path transformation based on configured KV version
- Users can select KV version when adding servers
## What Changed
### VaultClient (New File)
```typescript
// Automatically handles KV v1 vs v2 paths
const client = new VaultClient({
server,
credentials,
kvVersion: 2 // or 1 for legacy
});
// LIST - uses /metadata/ for KV v2
await client.list('secret/myapp/');
// KV v2 → GET /v1/secret/metadata/myapp/?list=true ✅
// KV v1 → GET /v1/secret/myapp/?list=true
// READ - uses /data/ for KV v2
await client.read('secret/myapp/config');
// KV v2 → GET /v1/secret/data/myapp/config ✅
// KV v1 → GET /v1/secret/myapp/config
```
### Path Transformation Logic
**KV v2:**
- `list('secret/myapp')``secret/metadata/myapp`
- `read('secret/myapp')``secret/data/myapp`
- `write('secret/myapp')``secret/data/myapp`
**KV v1:**
- All operations use paths as-is (no transformation)
### UI Updates
**Server Configuration:**
- Added KV version selector when adding servers
- Default: KV v2 (most common)
- Option: KV v1 (for legacy systems)
- Badge showing KV version on each server card
### New Features
1. **Automatic Path Handling**
- No need to manually add `/data/` or `/metadata/`
- Client handles it based on operation and KV version
2. **KV Version Detection**
- `client.detectKvVersion('secret')` - auto-detect if needed
3. **Metadata Operations** (KV v2 only)
- `client.readMetadata(path)` - get version history
- Returns versions, creation times, etc.
4. **Better Error Messages**
- "no handler for route" → suggests checking KV version
- Includes status codes and Vault error details
## File Changes
### New Files
- ✅ `src/services/vaultClient.ts` - Core Vault client
- ✅ `KV_VERSIONS.md` - Comprehensive KV v1/v2 guide
- ✅ `CORS_AND_CLIENT.md` - CORS and architecture docs
- ✅ `CHANGELOG.md` - Detailed changelog
### Modified Files
- ✅ `src/services/vaultApi.ts` - Now uses VaultClient
- ✅ `src/types.ts` - Added `kvVersion` to VaultServer
- ✅ `src/components/ServerSelector.tsx` - KV version selector
- ✅ `src/components/ServerSelector.css` - Badge styling
- ✅ `src/components/Dashboard.tsx` - Better error handling
## Why These Changes Matter
### ❌ Before (Problems)
```typescript
// Manual CORS headers (doesn't work)
headers: {
'Access-Control-Allow-Origin': '*' // ❌ Ignored by browser
}
// no-cors mode (breaks response reading)
mode: 'no-cors' // ❌ Can't read response body
// Raw API calls
fetch(`${url}/v1/${path}`) // ❌ No retries, timeouts, error handling
// Wrong paths for KV v2
fetch(`${url}/v1/secret/myapp?list=true`) // ❌ Should use /metadata/
```
### ✅ After (Solutions)
```typescript
// Proper Vault client
const client = new VaultClient({
server,
credentials,
kvVersion: 2,
timeout: 30000,
retries: 2
});
// Automatic path transformation
await client.list('secret/myapp');
// → Uses /metadata/ for KV v2 ✅
// → Uses direct path for KV v1 ✅
// Better errors
try {
await client.read(path);
} catch (error) {
if (error instanceof VaultError) {
console.log(error.statusCode); // 403, 404, etc.
console.log(error.errors); // Detailed Vault errors
}
}
```
## Testing Checklist
- [x] VaultClient compiles without errors
- [x] Path transformation for KV v1
- [x] Path transformation for KV v2
- [x] LIST uses /metadata/ for KV v2 ✅
- [x] READ uses /data/ for KV v2 ✅
- [x] WRITE uses /data/ for KV v2 ✅
- [x] UI shows KV version selector
- [x] UI shows KV version badge on servers
- [x] Better error messages
- [ ] Manual testing with real Vault KV v1
- [ ] Manual testing with real Vault KV v2
## Documentation
Comprehensive documentation added:
1. **`KV_VERSIONS.md`**
- KV v1 vs v2 comparison
- Path structure explained
- When to use each version
- Troubleshooting guide
2. **`CORS_AND_CLIENT.md`**
- Why client-side CORS headers don't work
- Why `mode: 'no-cors'` breaks things
- Proper Vault CORS configuration
- VaultClient architecture benefits
3. **`CHANGELOG.md`**
- Detailed list of changes
- Before/after comparisons
- Migration guide
## Summary
### Your Feedback ✅
1. ✅ **"Use a vault-client instead of raw API"**
- Created proper VaultClient class
- Production-ready with retries, timeouts, error handling
2. ✅ **"Make call on /secret/metadata"**
- LIST operations use `/metadata/` for KV v2
- READ/WRITE use `/data/` for KV v2
- Automatic path transformation
- Support for both KV v1 and v2
### Benefits
- 🎯 **Correct API endpoints** for KV v2
- 🔄 **Automatic retries** on failures
- ⏱️ **Timeout protection** prevents hanging
- 🛡️ **Better error handling** with detailed messages
- 🎨 **Clean API** - same code for v1 and v2
- 📚 **Comprehensive docs** explaining everything
- ✅ **Type-safe** with full TypeScript support
The application now properly handles both KV versions with the correct endpoints! 🎉

View File

@ -1,259 +0,0 @@
# KV v2 Enforcement - Simplification Complete
## ✅ All Changes Implemented
The application now **enforces KV v2** throughout, removing the complexity of supporting both KV v1 and v2. This simplifies the codebase and UI while focusing on the modern Vault standard.
## Changes Made
### 1. 🗑️ Removed KV Version Selection from UI
**ServerSelector.vue**:
- ✅ Removed KV version dropdown from "Add Server" form
- ✅ Removed `kvVersion` from `newServer` state
- ✅ Updated server cards to show static "KV v2" badge
- ✅ Simplified form validation and submission
**Before**:
```vue
<select v-model="newServer.kvVersion">
<option :value="2">KV v2 (recommended)</option>
<option :value="1">KV v1 (legacy)</option>
</select>
```
**After**:
```vue
<!-- KV v2 is enforced - no version selection needed -->
```
### 2. 🔧 Updated Type Definitions
**types.ts**:
- ✅ Removed `kvVersion?: 1 | 2` from `VaultServer` interface
- ✅ Added comment explaining KV v2 enforcement
- ✅ Simplified server object structure
**Before**:
```typescript
export interface VaultServer {
id: string;
name: string;
url: string;
description?: string;
kvVersion?: 1 | 2; // KV secret engine version (default: 2)
savedCredentials?: VaultCredentials;
}
```
**After**:
```typescript
export interface VaultServer {
id: string;
name: string;
url: string;
description?: string;
// KV v2 is enforced - no version selection needed
savedCredentials?: VaultCredentials;
}
```
### 3. ⚙️ Simplified VaultApi Service
**vaultApi.ts**:
- ✅ Removed `kvVersion` parameter from `createClient()`
- ✅ Hard-coded `kvVersion: 2` in VaultClient constructor
- ✅ Updated all method calls to remove version parameter
- ✅ Simplified `searchAllMounts()` logic
**Before**:
```typescript
private createClient(
server: VaultServer,
credentials: VaultCredentials,
kvVersion: 1 | 2 = 2
): VaultClient {
return new VaultClient({
server,
credentials,
timeout: 30000,
retries: 2,
kvVersion, // KV v2 by default (most common)
});
}
```
**After**:
```typescript
private createClient(
server: VaultServer,
credentials: VaultCredentials
): VaultClient {
return new VaultClient({
server,
credentials,
timeout: 30000,
retries: 2,
kvVersion: 2, // KV v2 is enforced
});
}
```
### 4. 📋 Updated Dashboard Display
**Dashboard.vue**:
- ✅ Mount point selector shows static "v2" for all mounts
- ✅ Removed conditional version display logic
- ✅ Simplified mount point rendering
**Before**:
```vue
{{ mount.path }}/ ({{ mount.type }} v{{ mount.options?.version || '1' }})
```
**After**:
```vue
{{ mount.path }}/ ({{ mount.type }} v2)
```
### 5. 🔐 Simplified SecretModal
**SecretModal.vue**:
- ✅ Always loads metadata and versions (no KV version check)
- ✅ Removed conditional metadata loading logic
- ✅ Updated footer text to reflect KV v2 enforcement
- ✅ Simplified error messages
**Before**:
```typescript
// Try to load metadata and versions (KV v2 only)
if (props.server.kvVersion === 2) {
await loadMetadataAndVersions();
}
```
**After**:
```typescript
// Load metadata and versions (KV v2 enforced)
await loadMetadataAndVersions();
```
## Benefits of KV v2 Enforcement
### 🎯 Simplified User Experience
- **No confusing choices** - users don't need to know about KV versions
- **Consistent behavior** - all features work the same way
- **Modern defaults** - KV v2 is the current Vault standard
- **Reduced cognitive load** - fewer options to understand
### 🔧 Cleaner Codebase
- **Less complexity** - no conditional logic for versions
- **Fewer parameters** - simplified method signatures
- **Better maintainability** - single code path to maintain
- **Reduced testing surface** - fewer edge cases
### 📊 Enhanced Features
- **Always available metadata** - version history, timestamps, etc.
- **Consistent API paths** - `/data/` and `/metadata/` endpoints
- **Better secret management** - soft deletes, version control
- **Audit capabilities** - full version history tracking
### 🚀 Performance Benefits
- **No version detection** - faster mount point processing
- **Optimized API calls** - direct KV v2 endpoint usage
- **Simplified caching** - consistent cache key generation
- **Reduced overhead** - no version-specific logic
## Technical Implementation
### API Endpoint Usage
All secret operations now use KV v2 endpoints:
- **List**: `/v1/{mount}/metadata/{path}?list=true`
- **Read**: `/v1/{mount}/data/{path}`
- **Write**: `/v1/{mount}/data/{path}`
- **Delete**: `/v1/{mount}/data/{path}`
- **Metadata**: `/v1/{mount}/metadata/{path}`
### Mount Point Detection
Mount points are detected via `/v1/sys/internal/ui/mounts` and filtered for:
- `type === 'kv'` (KV secret engines)
- `type === 'generic'` (legacy KV engines)
All detected KV mounts are treated as v2.
### Secret Modal Features
With KV v2 enforcement, the SecretModal always provides:
- **Current secret data** with JSON formatting
- **Complete metadata** including versions, timestamps
- **Version history** with ability to view any version
- **Audit trail** showing creation/modification times
## Migration Notes
### For Existing Users
- **No data loss** - existing server configurations preserved
- **Automatic upgrade** - all servers now treated as KV v2
- **Enhanced features** - metadata and versions now always available
- **Simplified interface** - no version selection needed
### For Vault Administrators
- **KV v2 required** - ensure all secret engines are KV v2
- **Migration path** - upgrade KV v1 engines to v2 if needed
- **Feature compatibility** - all advanced features require KV v2
### Vault KV v1 to v2 Migration
If you have KV v1 engines, upgrade them:
```bash
# Enable KV v2 engine
vault secrets enable -path=secret -version=2 kv
# Migrate data from v1 to v2 (manual process)
# Note: This requires custom scripting as there's no direct migration
```
## Error Handling
### KV v1 Compatibility
If the application encounters a KV v1 engine:
- **Metadata loading** will fail gracefully
- **Basic secret reading** will still work
- **Version history** will be unavailable
- **User feedback** indicates KV v2 features missing
### Graceful Degradation
The application handles KV v1 engines by:
- Showing error messages for metadata operations
- Continuing to function for basic secret operations
- Providing clear feedback about missing features
- Suggesting KV v2 upgrade in error messages
## Future Considerations
### Potential Enhancements
With KV v2 enforcement, future features could include:
- **Secret versioning UI** - visual diff between versions
- **Rollback functionality** - restore previous versions
- **Metadata editing** - custom metadata management
- **Deletion policies** - configure auto-deletion rules
- **Secret templates** - predefined secret structures
### Advanced KV v2 Features
Could be implemented:
- **Check-and-set operations** - prevent concurrent modifications
- **Secret patching** - partial updates to secrets
- **Metadata-only operations** - manage metadata without reading secrets
- **Bulk operations** - batch secret management
## Conclusion
**KV v2 enforcement successfully implemented**:
1. **🗑️ Removed version selection** - simplified UI
2. **🔧 Updated all services** - consistent KV v2 usage
3. **📋 Enhanced features** - metadata always available
4. **🚀 Improved performance** - optimized for single version
The application now provides a **streamlined, modern experience** focused on KV v2's advanced capabilities while maintaining **backward compatibility** through graceful degradation.
**Key Achievement**: Transformed from a dual-version system to a **focused, feature-rich KV v2 application** with enhanced metadata, versioning, and audit capabilities.

View File

@ -1,318 +0,0 @@
# HashiCorp Vault KV Secret Engine Versions
## Overview
HashiCorp Vault has two versions of the Key-Value (KV) secret engine:
- **KV v1**: Simple key-value storage (legacy)
- **KV v2**: Versioned secrets with metadata (recommended)
This application supports both versions and automatically handles the path differences.
## Key Differences
| Feature | KV v1 | KV v2 |
|---------|-------|-------|
| **Versioning** | ❌ No | ✅ Yes |
| **Metadata** | ❌ No | ✅ Yes |
| **Soft Delete** | ❌ No | ✅ Yes |
| **Path Structure** | Simple | Nested (data/metadata) |
| **API Calls** | Direct | Through /data or /metadata |
| **Rollback** | ❌ No | ✅ Yes |
| **Check-and-Set** | ❌ No | ✅ Yes |
## Path Structures
### KV v1
```
secret/myapp/database
secret/myapp/api-keys
secret/team/config
```
Simple, direct paths. What you see is what you get.
### KV v2
```
secret/data/myapp/database # For reading/writing secrets
secret/metadata/myapp/database # For metadata operations
```
KV v2 uses special path prefixes:
- `/data/` for reading and writing secret data
- `/metadata/` for listing and metadata operations
## How Our Client Handles This
### Automatic Path Transformation
Our `VaultClient` automatically transforms paths based on the KV version:
```typescript
// You write this:
await client.read('secret/myapp/database');
// KV v1: Uses path as-is
// → GET /v1/secret/myapp/database
// KV v2: Automatically adds /data/
// → GET /v1/secret/data/myapp/database
```
### List Operations
**KV v1:**
```typescript
await client.list('secret/myapp/');
// → LIST /v1/secret/myapp/?list=true
```
**KV v2:**
```typescript
await client.list('secret/myapp/');
// → LIST /v1/secret/metadata/myapp/?list=true
// (uses /metadata/ for listing)
```
### Read Operations
**KV v1:**
```typescript
const data = await client.read('secret/myapp/config');
// Returns: { username: '...', password: '...' }
```
**KV v2:**
```typescript
const data = await client.read('secret/myapp/config');
// Automatically unwraps: data.data.data → { username: '...', password: '...' }
```
### Write Operations
**KV v1:**
```typescript
await client.write('secret/myapp/config', {
username: 'admin',
password: 'secret'
});
// POST /v1/secret/myapp/config
// Body: { username: '...', password: '...' }
```
**KV v2:**
```typescript
await client.write('secret/myapp/config', {
username: 'admin',
password: 'secret'
});
// POST /v1/secret/data/myapp/config
// Body: { data: { username: '...', password: '...' } }
// (wrapped in data object)
```
## Configuring KV Version
### In the UI
When adding a Vault server:
1. Click "Add Server"
2. Fill in the server details
3. Select **KV Secret Engine Version**:
- **KV v2 (recommended)** - Default, most common
- **KV v1 (legacy)** - For older Vault installations
### Detecting KV Version
If you're unsure which version your Vault uses:
```bash
# Check your Vault server
vault secrets list -detailed
# Look for the "Options" column
# version=2 means KV v2
# No version or version=1 means KV v1
```
Or use the API:
```bash
curl -H "X-Vault-Token: $VAULT_TOKEN" \
$VAULT_ADDR/v1/sys/internal/ui/mounts/secret
```
Look for `"options": {"version": "2"}` in the response.
## When to Use KV v1 vs KV v2
### Use KV v2 (Recommended) When:
- ✅ Starting a new Vault installation
- ✅ You need versioning and rollback
- ✅ You want soft delete (undelete capability)
- ✅ You need to track secret history
- ✅ You want check-and-set operations
### Use KV v1 Only When:
- Legacy Vault installation that can't be upgraded
- Specific requirement to not version secrets
- Very simple use case without versioning needs
## Example Workflows
### Reading a Secret
```typescript
// Same code works for both versions!
const data = await client.read('secret/myapp/database');
console.log(data.username);
console.log(data.password);
```
### Listing Secrets
```typescript
// Same code works for both versions!
const keys = await client.list('secret/myapp/');
console.log(keys);
// ['config', 'database/', 'api-keys/']
```
### Searching Recursively
```typescript
// Uses list() internally, works with both versions
const results = await vaultApi.searchPaths(
server,
credentials,
'secret/',
'database'
);
```
## KV v2 Specific Features
### Metadata Operations
```typescript
// Only available in KV v2
const metadata = await client.readMetadata('secret/myapp/database');
console.log(metadata.current_version); // 5
console.log(metadata.versions);
// {
// "1": { created_time: "...", destroyed: false },
// "2": { created_time: "...", destroyed: false },
// "3": { created_time: "...", destroyed: true },
// "4": { created_time: "...", destroyed: false },
// "5": { created_time: "...", destroyed: false }
// }
```
### Version History
KV v2 keeps track of all versions:
- Can read previous versions
- Can undelete soft-deleted secrets
- Can permanently destroy specific versions
- Can destroy all versions
### Soft Delete vs Hard Delete
**Soft Delete (KV v2):**
```typescript
await client.delete('secret/myapp/database');
// Secret is "deleted" but can be undeleted
// Metadata still exists
```
**Hard Delete (KV v1):**
```typescript
await client.delete('secret/myapp/database');
// Secret is permanently gone
```
## Troubleshooting
### Error: "no handler for route"
```
Error: Vault API error: no handler for route 'secret/data/...'
```
**Cause**: Your Vault is using KV v1, but the client is configured for KV v2.
**Solution**: Edit the server configuration and change KV version to v1.
### Error: "1 error occurred: * permission denied"
This can happen if:
1. You don't have permission to the path
2. You're using the wrong KV version (v1 paths on v2 or vice versa)
**Solution**:
- Check your Vault policies
- Verify the KV version in server settings
### Paths Look Wrong
If you see paths like `secret/data/data/myapp`:
**Cause**: You're manually adding `/data/` when the client already does it for KV v2.
**Solution**: Use simple paths like `secret/myapp`. The client adds `/data/` or `/metadata/` automatically.
## Migration: KV v1 → KV v2
If you're migrating from KV v1 to KV v2:
1. **Backup all secrets** from KV v1
2. **Enable KV v2** on a new mount point
3. **Migrate secrets** to new paths
4. **Update application** to use new KV version
5. **Test thoroughly**
6. **Switch traffic** to new mount
In this GUI:
1. Add a new server entry with the same URL
2. Set KV version to v2
3. Use new mount path (e.g., `secretv2/` instead of `secret/`)
## Best Practices
1. **Use KV v2 for new installations**
2. **Configure correct version when adding servers**
3. **Don't mix KV v1 and v2 mount points** on same server without proper labeling
4. **Use simple paths** - let the client handle /data/ and /metadata/ prefixes
5. **Document which mounts use which version** for your team
## API Reference
All examples work transparently with both versions:
```typescript
// List
const keys = await client.list('secret/myapp/');
// Read
const data = await client.read('secret/myapp/config');
// Write
await client.write('secret/myapp/config', { key: 'value' });
// Delete
await client.delete('secret/myapp/config');
// Metadata (KV v2 only)
const meta = await client.readMetadata('secret/myapp/config');
```
## Summary
✅ **Both versions are fully supported**
✅ **Paths are automatically transformed**
✅ **Select correct version when adding server**
✅ **Use KV v2 for new installations**
✅ **Code is the same for both versions**
The client handles all the complexity, so you can focus on managing your secrets!

View File

@ -1,364 +0,0 @@
# Latest Features - Mount Point Detection & Multi-Mount Search
## 🎉 What's New
### 1. Login Verification ✅
**Before:** Login was assumed to work, no verification
**Now:** Login is verified by calling `/v1/sys/internal/ui/mounts`
- ✅ Confirms credentials are valid
- ✅ Provides immediate feedback
- ✅ Shows detailed error messages on failure
- ✅ Fails fast if credentials are invalid
```typescript
// On login:
const mountPoints = await vaultApi.verifyLoginAndGetMounts(server, credentials);
// ✓ Login verified
// ✓ Mount points detected
```
### 2. Automatic Mount Point Discovery 🔍
**Detects all KV secret engine mount points:**
- Queries `/v1/sys/internal/ui/mounts` on login
- Filters for KV secret engines only (`kv` or `generic` type)
- Auto-detects KV version (v1 or v2) from mount options
- Stores mount points in connection state
**Example Console Output:**
```
⚡ Verifying login and fetching mount points...
✓ Found 3 KV mount point(s): ["secret", "secret-v1", "team-secrets"]
✓ Logged in successfully.
```
### 3. Search Across All Mounts 🚀
**New Feature:** Optional multi-mount search
**UI Changes:**
- Checkbox: "Search across all mount points (N available)"
- Shows number of detected mount points
- Disabled when no mount points available
- **Off by default** (single path search)
**When Enabled:**
- Searches all detected KV mount points
- Each mount searched with correct KV version
- Results show mount point indicator: 📌
- Continues even if some mounts fail (permission denied)
**Search Results:**
```
📄 secret/prod/database/credentials
📌 secret
Depth: 2
📄 team-secrets/shared/database
📌 team-secrets
Depth: 1
```
### 4. Intelligent KV Version Handling
**Per-mount KV version detection:**
```typescript
// Each mount can have different KV version
secret/ → KV v2 (uses /metadata/ for LIST)
secret-v1/ → KV v1 (direct LIST)
team-secrets/ → KV v2 (uses /metadata/ for LIST)
```
**Automatic path transformation:**
- KV v2: `secret/``secret/metadata/` for LIST
- KV v2: `secret/``secret/data/` for READ/WRITE
- KV v1: `secret/``secret/` (no transformation)
## 📊 Technical Changes
### New API Methods
**`VaultClient.listMounts()`**
```typescript
const mounts = await client.listMounts();
// Returns all mount points with metadata
```
**`vaultApi.verifyLoginAndGetMounts()`**
```typescript
const mountPoints = await vaultApi.verifyLoginAndGetMounts(server, credentials);
// Verifies login + returns filtered KV mount points
```
**`vaultApi.searchAllMounts()`**
```typescript
const results = await vaultApi.searchAllMounts(
server,
credentials,
mountPoints,
searchTerm
);
// Searches across all provided mount points
```
### Updated Types
**`MountPoint` interface:**
```typescript
interface MountPoint {
path: string; // "secret"
type: string; // "kv"
description: string; // "key/value secret storage"
accessor: string; // "kv_abc123"
config: { ... };
options: {
version?: string; // "2" for KV v2
};
}
```
**`VaultConnection` interface:**
```typescript
interface VaultConnection {
server: VaultServer;
credentials: VaultCredentials;
isConnected: boolean;
lastConnected?: Date;
mountPoints?: MountPoint[]; // ← NEW
}
```
**`SearchResult` interface:**
```typescript
interface SearchResult {
path: string;
isDirectory: boolean;
depth: number;
mountPoint?: string; // ← NEW
}
```
### File Changes
**Modified:**
- ✅ `src/types.ts` - Added MountPoint, updated VaultConnection
- ✅ `src/services/vaultClient.ts` - Added listMounts()
- ✅ `src/services/vaultApi.ts` - Added verifyLoginAndGetMounts(), searchAllMounts()
- ✅ `src/components/PathSearch.tsx` - Added multi-mount search UI
- ✅ `src/components/PathSearch.css` - Styles for new UI elements
- ✅ `src/components/Dashboard.tsx` - Pass mountPoints to PathSearch
- ✅ `src/App.tsx` - Call verifyLoginAndGetMounts() on login
**New:**
- ✅ `MOUNT_POINTS.md` - Comprehensive documentation
## 🎯 Use Cases
### Use Case 1: I Don't Know Which Mount
**Scenario:** "I need the database credentials, but I don't know if they're in `secret/` or `team-secrets/`"
**Solution:**
```
1. ☑ Enable "Search across all mount points"
2. Search: "database"
3. Results show secrets from ALL mounts with indicators
```
### Use Case 2: Multi-Team Environment
**Scenario:** Organization with multiple teams, each with their own mount point
**Detected:**
```
- secret (shared)
- team-engineering-secrets
- team-ops-secrets
- team-data-secrets
```
**Benefit:** Search across all teams' secrets (if you have permission)
### Use Case 3: Fast Targeted Search
**Scenario:** "I know exactly where to look: `secret/prod/myapp/`"
**Solution:**
```
1. ☐ Disable "Search across all mount points"
2. Base Path: secret/prod/myapp/
3. Search: "api-key"
4. Fast, targeted results
```
## 🔒 Security & Permissions
### Required Permissions
**For login verification and mount discovery:**
```hcl
path "sys/internal/ui/mounts" {
capabilities = ["read"]
}
```
**For searching:**
```hcl
# KV v2
path "secret/metadata/*" {
capabilities = ["list"]
}
# KV v1
path "secret/*" {
capabilities = ["list"]
}
```
### Graceful Permission Handling
**What happens if you can't access a mount:**
```
🔍 Searching across 3 mount point(s)...
→ Searching in secret/
✓ 45 results
→ Searching in team-secrets/
✗ Error: permission denied
→ Searching in public-secrets/
✓ 23 results
✓ Found 68 total result(s) across all mounts
```
- ✅ Continues with other mounts
- ✅ Logs error in console
- ✅ Returns partial results
- ✅ No error thrown to user
## ⚡ Performance
### Caching Strategy
**Each mount path cached separately:**
```
Cache key: "server123:list:secret/"
Cache key: "server123:list:team-secrets/"
Cache key: "server123:list:public-secrets/"
```
**Benefits:**
- First search: API calls to all mounts
- Subsequent searches: Instant from cache
- Cache respects max size and expiration
### Search Optimization
**Sequential search with early exit:**
```
1. Search mount 1 → 400 results
2. Search mount 2 → 300 results
3. Search mount 3 → 300 results
4. Total: 1000 results → STOP (max reached)
5. Mount 4+ not searched
```
## 🎨 UI/UX Improvements
### Login Process
**Visual feedback:**
```
[Connecting...] → [✓ Login verified] → [✓ Found 3 mount points]
```
**On failure:**
```
[Connecting...] → [✗ Error: permission denied]
[Please check credentials]
```
### Search Interface
**Dynamic UI:**
- Checkbox shows mount count: "(3 available)"
- Checkbox disabled if no mounts detected
- Base path field hidden when searching all mounts
- Results show mount indicator when relevant
**Helpful hints:**
```
Search Tips:
• Search all mounts: searches across all KV secret engines
(detected: secret, secret-v1, team-secrets)
• Base path: when not searching all mounts, specify starting path
• Results are cached to prevent excessive API calls
```
## 📝 Console Output Examples
### Successful Login
```
⚡ Verifying login and fetching mount points...
✓ Found 3 KV mount point(s): ["secret", "secret-v1", "team-secrets"]
✓ Logged in successfully. Found 3 KV mount point(s).
```
### Failed Login
```
⚡ Verifying login and fetching mount points...
✗ Login verification failed: permission denied
```
### Multi-Mount Search
```
🔍 Searching across 3 mount point(s)...
→ Searching in secret/
⚡ API call for list: secret/metadata/
⚡ API call for list: secret/metadata/prod/
⚡ API call for list: secret/metadata/dev/
✓ Cache hit for list: secret/metadata/shared/
→ Searching in secret-v1/
✓ Cache hit for list: secret-v1/
→ Searching in team-secrets/
⚡ API call for list: team-secrets/metadata/
✓ Found 145 total result(s) across all mounts
```
## 🔧 Configuration
All existing configuration still applies:
**Cache Settings:**
- Max cache size (MB)
- Cache expiration time (minutes)
- Enable/disable caching
**Search Settings:**
- Max search depth (applies per mount)
- Max search results (applies globally across all mounts)
## 📚 Documentation
**New comprehensive guide:**
- `MOUNT_POINTS.md` - Everything about mount point detection and multi-mount search
**Updated guides:**
- `README.md` - Project overview
- `USAGE.md` - Usage instructions
- `FEATURES.md` - Feature list
## 🎯 Summary
**Login verification** - No more blind login attempts
**Auto-detect mount points** - Discover all KV secret engines
**Search all mounts** - Optional cross-mount search
**Mount indicators** - Know which mount each result is from
**Smart KV handling** - Per-mount version detection
**Graceful errors** - Continue on permission denied
**Performance optimized** - Caching + early exit
**Security conscious** - Respects Vault ACLs
This makes discovering secrets in large Vault deployments **much easier**! 🚀

View File

@ -1,395 +0,0 @@
# Mount Point Detection and Multi-Mount Search
## Overview
The application now automatically detects all available KV secret engine mount points when you log in, and allows you to search across all of them simultaneously.
## How It Works
### 1. Login Verification
When you log in, the application:
1. **Verifies your credentials** by calling `/v1/sys/internal/ui/mounts`
2. **Discovers all mount points** available on the Vault server
3. **Filters for KV secret engines** (type: `kv` or `generic`)
4. **Detects KV versions** automatically from mount options
5. **Stores mount points** in the connection state
```typescript
// Example mount points detected:
[
{ path: "secret", type: "kv", options: { version: "2" } },
{ path: "cubbyhole", type: "cubbyhole", options: {} },
{ path: "identity", type: "identity", options: {} },
{ path: "sys", type: "system", options: {} }
]
// Filtered to KV engines only:
[
{ path: "secret", type: "kv", options: { version: "2" } }
]
```
### 2. Search Modes
The application supports two search modes:
#### Mode 1: Single Base Path (Default)
- ✅ Search within a specific mount point/path
- ✅ Fast and targeted
- ✅ Use when you know where to look
```typescript
// Search only in secret/myapp/
Base Path: secret/myapp/
Search Term: database
```
#### Mode 2: All Mount Points
- ✅ Search across all detected KV mount points
- ✅ Comprehensive coverage
- ✅ Use when you don't know which mount contains the secret
- ⚠️ Slower (searches multiple mount points sequentially)
```typescript
// Searches: secret/, secret-v1/, team-secrets/, etc.
☑ Search across all mount points (3 available)
Search Term: database
```
## UI Features
### Login Process
**Before (without verification):**
```
1. Enter credentials
2. Click "Connect"
3. Hope it works 🤞
```
**After (with verification):**
```
1. Enter credentials
2. Click "Connect"
3. ✓ Login verified via API call
4. ✓ Mount points detected
5. ✓ "Found 3 KV mount point(s)" message
6. If login fails: detailed error message
```
### Search Interface
**Checkbox:** "Search across all mount points"
- Shows number of available mounts: "(3 available)"
- Disabled if no mount points detected
- Off by default (single path search)
**When Enabled:**
- Base Path field hidden (not needed)
- Searches all detected KV mount points
- Results show mount point indicator: 📌
**When Disabled:**
- Base Path field visible
- Normal single-path search behavior
### Search Results
**With Single Path Search:**
```
📄 secret/myapp/database/credentials
Depth: 2
```
**With All Mounts Search:**
```
📄 secret/myapp/database/credentials
📌 secret
Depth: 2
📄 team-secrets/shared/database
📌 team-secrets
Depth: 1
```
## Technical Implementation
### API Call: `/v1/sys/internal/ui/mounts`
**Request:**
```http
GET /v1/sys/internal/ui/mounts HTTP/1.1
Host: vault.example.com
X-Vault-Token: your-token
```
**Response:**
```json
{
"data": {
"secret/": {
"type": "kv",
"description": "key/value secret storage",
"accessor": "kv_abc123",
"config": {
"default_lease_ttl": 0,
"max_lease_ttl": 0
},
"options": {
"version": "2"
}
},
"cubbyhole/": {
"type": "cubbyhole",
"description": "per-token private secret storage",
...
},
...
}
}
```
### Mount Point Filtering
Only KV secret engines are included:
- `type === 'kv'` - KV v1 or v2
- `type === 'generic'` - Legacy KV v1
Other types are excluded:
- `cubbyhole` - Per-token storage (not searchable)
- `identity` - Identity management
- `system` - System backend
- `pki` - PKI certificates
- `aws`, `azure`, `gcp` - Dynamic secrets
- etc.
### KV Version Detection
```typescript
// From mount options
const kvVersion = mount.options?.version === '2' ? 2 : 1;
// Automatically used for path transformation
// KV v2: secret/ → secret/metadata/ for LIST
// KV v1: secret/ → secret/ as-is
```
### Search Algorithm
**Single Path:**
```
1. Search in base path
2. Recurse into subdirectories
3. Return results
```
**All Mounts:**
```
1. For each KV mount point:
a. Detect KV version
b. Search from mount root
c. Recurse into subdirectories
d. Add results with mount indicator
e. Check max results limit
2. Combine all results
3. Return aggregated results
```
## Performance Considerations
### Caching Strategy
**All searches are cached:**
- Single path search: Cached per path
- All mounts search: Each mount path cached separately
- Cache key includes mount point
- Repeated searches are instant
**Cache Benefits:**
- Prevents redundant API calls
- Faster subsequent searches
- Respects DDoS prevention limits
### Search Limits
**Applied globally across all mounts:**
```typescript
config.search.maxResults = 1000; // Total across all mounts
config.search.maxDepth = 10; // Per mount point
// Example:
// Mount 1: 400 results, depth 8 ✓
// Mount 2: 300 results, depth 7 ✓
// Mount 3: 300 results, depth 5 ✓
// Total: 1000 results - stops here
```
### Performance Tips
1. **Use single path search** when you know the mount
2. **Enable all mounts search** for discovery
3. **Adjust max results** in settings if needed
4. **Use specific search terms** to limit results
5. **Check console** for per-mount progress
## Error Handling
### Login Verification Fails
```
Error: Login verification failed: permission denied
Possible causes:
1. Invalid credentials
2. Token expired
3. No permission to list mounts
4. Network/CORS issues
Solution: Check credentials and permissions
```
### Mount Point Access Denied
```
✓ Found 3 KV mount point(s): secret, secret-v1, team-secrets
→ Searching in secret/
✓ 45 results
→ Searching in secret-v1/
✗ Error: permission denied
→ Searching in team-secrets/
✓ 23 results
✓ Found 68 total result(s) across all mounts
```
**Behavior:**
- Continues with other mounts
- Logs error for failed mount
- Returns partial results
- User sees console warning
## Use Cases
### Use Case 1: Discovery
**Scenario:** "I know there's a database credential somewhere, but I don't remember which mount."
**Solution:**
```
1. ☑ Enable "Search across all mount points"
2. Search Term: "database"
3. Get results from all mounts:
- secret/prod/database
- secret/dev/database
- team-secrets/shared/database
```
### Use Case 2: Specific Search
**Scenario:** "I need to find all Redis configs in the production secrets."
**Solution:**
```
1. ☐ Disable "Search across all mount points"
2. Base Path: secret/prod/
3. Search Term: "redis"
4. Fast, targeted results
```
### Use Case 3: Multi-Team Environment
**Scenario:** Multiple teams with separate mount points
**Detected mounts:**
```
- secret (shared)
- team-a-secrets
- team-b-secrets
- team-c-secrets
```
**All mounts search:**
- Finds secrets across all team mounts
- Shows which mount each result is in
- Respects permissions (skips unauthorized mounts)
## Console Output Examples
### Login:
```
⚡ Verifying login and fetching mount points...
✓ Found 3 KV mount point(s): ["secret", "secret-v1", "team-secrets"]
✓ Logged in successfully. Found 3 KV mount point(s).
```
### Single Path Search:
```
⚡ API call for list: secret/myapp/
✓ Cache hit for list: secret/myapp/database/
🔍 Searching...
✓ Found 12 result(s) in 0.45s
```
### All Mounts Search:
```
🔍 Searching across 3 mount point(s)...
→ Searching in secret/
✓ 45 results from secret
→ Searching in secret-v1/
✓ 23 results from secret-v1
→ Searching in team-secrets/
✗ Error searching team-secrets: permission denied
✓ Found 68 total result(s) across all mounts
```
## Security Implications
### What's Exposed
**Mount point names and structure:**
- ✅ Visible to anyone who can log in
- ✅ No secret data exposed
- ✅ Only KV mounts shown
- ✅ Respects Vault ACLs
### Permissions
**Required permissions:**
```hcl
# To list mounts (login verification)
path "sys/internal/ui/mounts" {
capabilities = ["read"]
}
# To search in a mount
path "secret/metadata/*" { # KV v2
capabilities = ["list"]
}
path "secret/*" { # KV v1
capabilities = ["list"]
}
```
### Failed Permission Handling
- ✅ Graceful degradation
- ✅ Continues with accessible mounts
- ✅ Logs denied mounts
- ✅ No error thrown to user
## Summary
**Login now verifies credentials** via API call
**Mount points auto-detected** on login
**Search across all mounts** optional feature (off by default)
**Mount indicator** in search results
**Automatic KV version detection** per mount
**Graceful error handling** for inaccessible mounts
**Performance optimized** with caching
**Security conscious** - respects Vault ACLs
This feature makes it much easier to discover secrets across large Vault deployments with multiple mount points!

218
README.md
View File

@ -1,205 +1,45 @@
# Browser Vault GUI
A modern Vue 3 + TypeScript frontend for HashiCorp Vault with Tailwind CSS and DaisyUI. This is an alternative web interface that allows you to connect to multiple Vault servers and manage your secrets.
A modern, user-friendly web interface for HashiCorp Vault that runs entirely in your browser.
## Features
- 🔐 **Multiple Vault Servers**: Add and manage connections to multiple Vault instances
- 🔑 **Multiple Auth Methods**: Support for Token, Username/Password, and LDAP authentication
- 🔍 **Recursive Path Search**: Search through vault paths recursively with configurable depth limits
- 💾 **Smart Caching**: API responses are cached in localStorage to prevent DDoS and reduce server load
- ⚙️ **Configurable Settings**: Adjust cache size, expiration time, search depth, and result limits
- 📊 **Cache Statistics**: Monitor cache usage with real-time statistics
- 🎨 **Modern UI**: Beautiful, responsive interface with dark/light mode support (Tailwind + DaisyUI)
- 🚀 **Fast**: Built with Vite for lightning-fast development and builds
- 🔒 **Secure by Default**: Credentials stored in memory only (optional localStorage with warnings)
## Getting Started
## Installation
### Prerequisites
- Node.js 18+ and npm (or yarn/pnpm)
You'll need:
- Node.js (version 18 or higher)
- A running HashiCorp Vault server
- Basic knowledge of your Vault server URL and credentials
### Installation
### Quick Start
1. Install dependencies:
```bash
npm install
```
1. **Download the project**
```bash
git clone <repository-url>
cd browser-vault-gui
```
2. Start the development server:
```bash
npm run dev
```
2. **Install dependencies**
```bash
pnpm install
```
3. Open your browser and navigate to `http://localhost:5173`
3. **Start the development server**
```bash
pnpm run dev
```
4. **Open your browser**
- Navigate to `http://localhost:5173`
- Add your Vault server details
- Log in with your Vault credentials
### Building for Production
To create a production build:
```bash
npm run build
pnpm run build
```
The built files will be in the `dist/` directory.
## Usage
1. **Add a Vault Server**:
- Click "Add Server" button
- Enter server name, URL, and optional description
- Click "Add Server" to save
2. **Connect to a Server**:
- Select a server from the list
- Choose your authentication method
- Enter your credentials
- Click "Connect"
3. **Browse and Search Secrets**:
- Once connected, use the secret browser to read secrets
- Enter the path to your secret (e.g., `secret/data/myapp/config`)
- Click "Read Secret" or press Enter
- Or use the "🔍 Search" button to recursively search for paths
- Search results are cached automatically
4. **Configure Settings**:
- Click "⚙️ Settings" to adjust cache and search parameters
- Set maximum cache size (in MB)
- Configure cache expiration time
- Adjust maximum search depth and result limits
- View cache statistics and clear cache if needed
## Implementation Notes
This application includes a **working Vault API client** with the following features:
✅ **Implemented:**
- Read secrets from Vault
- List secrets at a given path
- Recursive path search with caching
- Configurable cache system
- Settings management
🚧 **To be implemented:**
- Write/update secrets
- Delete secrets
- Policy management
- Audit log viewing
- Authentication flows (currently requires pre-existing token/credentials)
### CORS Configuration
To use this with your Vault server, you'll need to configure CORS. Add the following to your Vault server configuration:
```hcl
ui = true
listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = 1
cors_enabled = true
cors_allowed_origins = ["http://localhost:5173", "https://yourdomain.com"]
cors_allowed_headers = ["*"]
}
```
### Vault API Endpoints
The Vault HTTP API endpoints you'll need to implement:
- **Authentication**: `POST /v1/auth/<method>/login`
- **Read Secret**: `GET /v1/<path>`
- **Write Secret**: `POST /v1/<path>`
- **Delete Secret**: `DELETE /v1/<path>`
- **List Secrets**: `LIST /v1/<path>` (or `GET /v1/<path>?list=true`)
Remember to include the `X-Vault-Token` header with your authentication token for all authenticated requests.
## Security Considerations
⚠️ **Important Security Notes**:
- This application stores Vault server URLs and cached API responses in localStorage
- **Credentials are NOT persisted by default** - they are only kept in memory during the active session
- Cached responses may contain sensitive secret paths and secret data
- Always use HTTPS URLs for production Vault servers
- Be aware of CORS restrictions when connecting to Vault servers
### ⚠️ Optional Credential Saving (NOT RECOMMENDED)
The app includes an **optional** feature to save credentials locally:
- **Default**: Credentials are NEVER saved ✅ (Recommended)
- **Optional**: Users can choose to save credentials with explicit warnings ⚠️
**If you enable credential saving:**
- A prominent security warning is shown before saving
- Credentials are stored in **plain text** in localStorage
- Anyone with access to your browser can read them
- This violates most security policies
- **Only use for personal development/testing**
See `SECURITY_CREDENTIALS.md` for detailed security analysis.
### Cache Security
The cache stores:
- ✅ Secret paths and directory listings (for search performance)
- ❌ **Secret data is NEVER cached** (always fetched fresh for security)
- ⚠️ Credentials (ONLY if user explicitly enables with warnings)
Cache can be cleared manually from Settings.
## Technology Stack
- **Vue 3** - Progressive JavaScript framework with Composition API
- **TypeScript** - Type safety throughout
- **Tailwind CSS** - Utility-first CSS framework
- **DaisyUI** - Beautiful component library for Tailwind
- **Vite** - Lightning-fast build tool and dev server
- **Custom Vault Client** - Browser-compatible Vault HTTP API client with retries, timeouts, and error handling
## Development
### Project Structure
```
src/
├── components/ # Vue 3 components
│ ├── ServerSelector.vue
│ ├── LoginForm.vue
│ ├── Dashboard.vue
│ ├── PathSearch.vue
│ └── Settings.vue
├── services/
│ ├── vaultClient.ts # Low-level Vault HTTP API client
│ └── vaultApi.ts # High-level API with caching
├── utils/
│ └── cache.ts # Cache management system
├── types.ts # TypeScript type definitions
├── config.ts # Application configuration
├── App.vue # Main application component
├── main.ts # Application entry point
└── style.css # Tailwind CSS imports
```
### Scripts
- `npm run dev` - Start development server (Vite)
- `npm run build` - Build for production (Vue TSC + Vite)
- `npm run preview` - Preview production build
- `npm run lint` - Run ESLint (Vue + TypeScript)
### Migration Note
This project was recently migrated from React to Vue 3. See `VUE_MIGRATION.md` for details.
## License
This project is open source and available under the MIT License.
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
The built files will be in the `dist` folder, ready to deploy to any web server.

View File

@ -1,294 +0,0 @@
# Saved Credentials Feature - Security Considerations
## ⚠️ WARNING: USE AT YOUR OWN RISK
This feature allows you to save Vault credentials (tokens, usernames, passwords) in your browser's localStorage for convenience. **This is NOT recommended for production or sensitive environments.**
## How It Works
### Saving Credentials
1. When logging in, check the **"⚠️ Save credentials locally"** checkbox
2. A security warning modal will appear on first use
3. Read and acknowledge the risks
4. Credentials are saved to localStorage (plain text)
5. On next login, credentials are pre-filled
### Visual Indicators
- Servers with saved credentials show a **🔓 Saved Credentials** badge
- The checkbox is pre-checked if credentials exist
- Warning styling (yellow/orange) throughout the UI
### Removing Saved Credentials
**Option 1: Uncheck the box**
- Uncheck "Save credentials locally"
- Login again
- Credentials are removed from localStorage
**Option 2: Remove the server**
- Delete the server from the list
- All associated data (including credentials) is removed
## Security Risks
### ❌ What's Wrong With Saving Credentials
1. **Plain Text Storage**
- Credentials are stored unencrypted in localStorage
- Easily accessible via browser DevTools (`localStorage.getItem('vaultServers')`)
- No encryption, obfuscation, or protection
2. **Browser Extension Access**
- Any browser extension can read localStorage
- Malicious extensions can steal credentials
- No way to restrict access
3. **Shared Computer Risk**
- Anyone with physical access can:
- Open browser DevTools
- Read localStorage
- Copy credentials
4. **XSS Vulnerability**
- If the app has an XSS vulnerability, credentials are exposed
- localStorage is accessible from JavaScript
5. **Browser Sync**
- Some browsers sync localStorage across devices
- Credentials might be synced to untrusted devices
- Shared across all synced browsers
6. **Compliance Issues**
- Violates most security policies
- Fails SOC 2, ISO 27001, PCI DSS requirements
- May violate company IT policies
7. **No Audit Trail**
- Can't track who accessed credentials
- No logging of credential usage
- Can't revoke access if device is lost
8. **Session Persistence**
- Credentials persist across browser restarts
- No automatic expiration
- Manual logout doesn't clear saved credentials
## Viewing Saved Credentials
Anyone can view saved credentials:
```javascript
// Open browser DevTools console
const servers = JSON.parse(localStorage.getItem('vaultServers'))
console.log(servers)
// View credentials for first server
console.log(servers[0].savedCredentials)
```
Output:
```json
{
"serverId": "my-vault",
"authMethod": "token",
"token": "hvs.CAESIJ5U8..." // ← Exposed!
}
```
## When Is It (Maybe) Acceptable?
Use saved credentials ONLY if ALL of these are true:
### ✅ Acceptable Use Cases
1. **Development/Testing**
- Non-production Vault server
- Test data only, no real secrets
- Personal development machine
2. **Personal Use**
- Personal computer, not shared
- You understand the risks
- You accept responsibility
3. **Low-Value Secrets**
- Development API keys
- Non-sensitive test data
- Throwaway tokens
4. **Short-Lived Tokens**
- Tokens expire quickly (< 1 hour)
- Limited permissions
- Easy to rotate
### ❌ NEVER Use For
1. **Production Vault Servers**
2. **Shared Computers**
3. **Work/Corporate Laptops**
4. **Public Computers**
5. **Sensitive Data**
6. **Long-Lived Tokens**
7. **High-Privilege Accounts**
8. **Compliance-Required Systems**
## Better Alternatives
### Recommended: Don't Save Credentials
1. **Re-login Each Session**
- Most secure option
- Only credentials in memory
- Auto-cleared on logout/close
2. **Use Password Manager**
- Browser password manager
- 1Password, LastPass, Bitwarden
- Encrypted storage
- Auto-fill support
3. **Short-Lived Tokens**
- Generate tokens with short TTL
- Expire after 1-8 hours
- Automatically revoked
4. **SSO/OIDC Authentication**
- Use Vault's OIDC auth method
- Leverage existing SSO
- No password storage needed
5. **Auto-Logout Timer**
- Implement session timeout
- Auto-logout after inactivity
- Clear credentials from memory
## Implementation Details
### Where Credentials Are Stored
```
localStorage['vaultServers'] = JSON array of server objects
Each server object can contain:
{
"id": "server-id",
"name": "My Vault",
"url": "https://vault.example.com",
"kvVersion": 2,
"savedCredentials": { ← This is the dangerous part
"serverId": "server-id",
"authMethod": "token",
"token": "hvs.CAESIJ5U8..." ← Plain text!
}
}
```
### Security Warning Modal
The app shows a prominent warning before saving credentials:
```
⚠️ Security Warning
This is NOT recommended for security reasons!
If you save credentials:
- Your token/password will be stored in plain text
- Anyone with access to your browser can read them
- Browser extensions can access localStorage
- If your computer is compromised, credentials are exposed
- This violates most security policies
Only use this if:
- You're on a personal, secure device
- You understand the security risks
- You're using a development/test Vault server
Better alternatives:
• Use short-lived tokens
• Re-login each session
• Use a password manager
• Enable auto-logout timeout
```
User must explicitly click "I Understand the Risks - Save Anyway"
## Console Warnings
The app logs warnings when credentials are saved:
```
⚠️ Credentials saved to localStorage (insecure!)
```
## Future Improvements
Potential enhancements (not implemented):
1. **Encryption**
- Encrypt credentials with a master password
- Use Web Crypto API
- Still vulnerable but better than plain text
2. **Session Storage**
- Use sessionStorage instead of localStorage
- Cleared when tab is closed
- Doesn't persist across browser restarts
3. **Auto-Expiration**
- Automatically clear credentials after N days
- Require re-authentication
- Reduce exposure window
4. **Browser Warnings**
- Show persistent warning in UI when credentials are saved
- Remind user on each login
- Make it more obvious
5. **Credential Rotation**
- Prompt user to rotate tokens
- Integration with Vault's token renewal
- Automatic token refresh
## Comparison: Save vs Don't Save
| Aspect | Don't Save (Default) | Save Credentials |
|--------|---------------------|------------------|
| **Security** | ✅ Secure | ❌ Insecure |
| **Convenience** | ⚠️ Must re-login | ✅ Auto-login |
| **Compliance** | ✅ Compliant | ❌ Violates policies |
| **Risk if stolen** | ✅ Low | ❌ High |
| **Browser restart** | Must re-login | ✅ Stays logged in |
| **Shared computer** | ✅ Safe | ❌ Dangerous |
| **Audit trail** | ✅ Per-session | ❌ None |
| **Token expiration** | ✅ Natural | ⚠️ Manual |
## Responsible Disclosure
If you find saved credentials in localStorage:
1. **Don't use them** - That would be unauthorized access
2. **Report it** - Inform the credentials owner
3. **Secure the device** - Help secure the compromised device
4. **Rotate credentials** - All saved credentials should be rotated
## Conclusion
### ⚠️ The Bottom Line
**Saving credentials is a convenience feature with serious security trade-offs.**
- ✅ **Convenient** for personal development
- ❌ **Dangerous** for anything sensitive
- ⚠️ **Use at your own risk**
**Default behavior (no saving) is recommended for everyone.**
If you choose to save credentials, you accept full responsibility for any security consequences.
---
*This feature exists because users requested it, but the developers strongly advise against using it in any security-conscious environment.*

240
USAGE.md
View File

@ -1,240 +0,0 @@
# Usage Guide
## Quick Start
### 1. Install and Run
```bash
npm install
npm run dev
```
Open http://localhost:5173 in your browser.
### 2. Add Your First Vault Server
1. Click **"+ Add Server"**
2. Fill in the form:
- **Server Name**: e.g., "Production Vault"
- **Server URL**: e.g., "https://vault.example.com"
- **Description**: Optional, e.g., "Production environment vault"
3. Click **"Add Server"**
### 3. Connect to Vault
1. Select your server from the list
2. Choose authentication method:
- **Token**: Paste your vault token
- **Username & Password**: Enter credentials
- **LDAP**: Enter LDAP credentials
3. Click **"Connect"**
### 4. Browse Secrets
#### Read a Secret Directly
1. Enter the full path in the "Secret Path" field
- Example: `secret/data/myapp/database`
2. Press Enter or click **"Read Secret"**
3. The secret data will appear below
#### Search for Secrets
1. Click **"🔍 Search"** button
2. Enter a **Base Path** (where to start searching)
- Example: `secret/`
3. Enter a **Search Term**
- Example: `database` (will find all paths containing "database")
4. Click **"Search"**
5. Results appear showing:
- 📁 Directories (not clickable)
- 📄 Secrets (clickable to view)
6. Click **"View"** on any secret to read it
### 5. Configure Settings
Click **"⚙️ Settings"** to adjust:
#### Cache Settings
- **Enable cache**: Toggle caching on/off
- **Maximum cache size**: How much data to cache (in MB)
- **Cache expiration**: How long cached data remains valid (in minutes)
#### Search Settings
- **Maximum search depth**: How deep to recurse (prevents infinite loops)
- **Maximum search results**: Limit number of results returned
#### Cache Statistics
View real-time cache usage:
- Total size of cached data
- Number of cached entries
- Age of oldest/newest entries
- **Clear Cache** button to reset
## Advanced Usage
### Understanding the Cache
The cache system prevents excessive API calls to your Vault server:
1. **First Request**: API call is made, result is cached
2. **Subsequent Requests**: Data returned from cache (instant)
3. **Cache Expiration**: After configured time, next request will hit the API again
**Cache Key Format**: `{serverId}:{operation}:{path}`
Example: `abc-123:list:secret/data/myapp/`
### Search Behavior
The recursive search:
1. Lists all items at the base path
2. For each item:
- If it matches the search term, it's added to results
- If it's a directory, recursively search inside it
3. Stops when:
- Max depth is reached
- Max results are found
- No more paths to explore
**Performance Tips**:
- Use specific base paths to limit search scope
- Results are cached, so repeated searches are fast
- Adjust max depth for deep directory structures
### Working with Different Auth Methods
#### Token Authentication
```
Token: s.1234567890abcdef
```
Best for: Development, CI/CD, service accounts
#### Username/Password
```
Username: john.doe
Password: ••••••••
```
Best for: Interactive users, testing
#### LDAP
```
Username: john.doe
Password: ••••••••
```
Best for: Enterprise users with LDAP integration
## Examples
### Example 1: Finding Database Credentials
1. Connect to your vault server
2. Click "🔍 Search"
3. Base Path: `secret/`
4. Search Term: `database`
5. View results and click on the relevant secret
6. Copy the credentials you need
### Example 2: Browsing Application Secrets
1. Connect to vault
2. Enter path: `secret/data/myapp/`
3. Note the structure
4. Navigate to specific secrets:
- `secret/data/myapp/config`
- `secret/data/myapp/database`
- `secret/data/myapp/api-keys`
### Example 3: Managing Cache
1. Use the application normally
2. Open Settings to view cache stats
3. If cache grows too large or contains stale data:
- Adjust cache size limit
- Reduce expiration time
- Or click "Clear Cache"
## Troubleshooting
### CORS Errors
If you see CORS errors in the console:
1. Configure your Vault server to allow CORS
2. Add your frontend URL to `cors_allowed_origins`
3. Restart your Vault server
Example Vault config:
```hcl
listener "tcp" {
cors_enabled = true
cors_allowed_origins = ["http://localhost:5173"]
}
```
### Authentication Fails
- Verify your token/credentials are correct
- Check token hasn't expired
- Ensure you have proper permissions in Vault
- Check Vault server URL is correct
### Search Returns No Results
- Verify the base path exists and you have permission to list it
- Try a broader search term
- Check max depth isn't too low
- Ensure secrets exist at that path
### Cache Issues
- Clear cache from Settings if data seems stale
- Check cache expiration time isn't too long
- Verify localStorage isn't full (browser limit ~5-10MB)
## Best Practices
1. **Security**:
- Always use HTTPS in production
- Don't share tokens
- Log out when done
- Clear cache if on shared computer
2. **Performance**:
- Use specific base paths for searches
- Adjust cache settings based on your usage
- Increase cache expiration if secrets change rarely
- Decrease for frequently updated secrets
3. **Organization**:
- Name servers clearly
- Add descriptions to help identify servers
- Use consistent path naming in Vault
- Structure secrets logically
4. **Maintenance**:
- Periodically clear cache
- Review cache statistics
- Adjust settings as usage patterns change
- Remove unused vault server configurations
## Keyboard Shortcuts
- **Enter** in Secret Path field: Read the secret
- **Enter** in Search Term field: Start search
- **Esc** in Settings modal: Close settings
## Data Storage
### What's Stored in localStorage:
- ✅ Vault server configurations (name, URL, description)
- ✅ Application settings (cache size, search limits, etc.)
- ✅ Cached API responses (paths, secrets)
### What's NOT Stored:
- ❌ Vault tokens
- ❌ Passwords
- ❌ Any credentials
Credentials are only kept in memory during your active session and are lost when you logout or close the tab.

View File

@ -1,345 +0,0 @@
# Vue 3 Migration Complete! 🎉
## What Changed
### ✅ Complete Rewrite from React to Vue 3 + Tailwind + DaisyUI
The entire UI layer has been converted while keeping all business logic intact!
## New Stack
- **Vue 3** with Composition API (`<script setup>`)
- **TypeScript** (fully typed)
- **Tailwind CSS** for utility-first styling
- **DaisyUI** for beautiful pre-built components
- **Vite** (already using it, no change)
## What Stayed the Same
**All business logic is untouched:**
- ✅ `src/services/vaultClient.ts` - Core Vault client
- ✅ `src/services/vaultApi.ts` - API with caching
- ✅ `src/utils/cache.ts` - Cache management
- ✅ `src/config.ts` - Configuration system
- ✅ `src/types.ts` - TypeScript interfaces
These are pure TypeScript and work identically in Vue!
## New Files
### Configuration
- `tailwind.config.js` - Tailwind + DaisyUI config
- `postcss.config.js` - PostCSS config for Tailwind
- `src/env.d.ts` - Vue type definitions
- `src/main.ts` - Vue app entry point (replaces main.tsx)
- `src/style.css` - Tailwind imports + custom styles
### Components (All .vue files)
- `src/App.vue`
- `src/components/ServerSelector.vue`
- `src/components/LoginForm.vue`
- `src/components/Dashboard.vue`
- `src/components/PathSearch.vue`
- `src/components/Settings.vue`
## Deleted Files
**All React files removed:**
- ❌ Deleted all `.tsx` files
- ❌ Deleted all `.css` component files
- ❌ Deleted React-specific config
## Setup Instructions
### 1. Install Dependencies
```bash
npm install
```
This will install:
- Vue 3
- Tailwind CSS
- DaisyUI
- Vue TypeScript compiler
- All necessary dev dependencies
### 2. Run Development Server
```bash
npm run dev
```
### 3. Build for Production
```bash
npm run build
```
## Key Vue 3 Patterns Used
### Composition API with `<script setup>`
```vue
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
const increment = () => count.value++
</script>
<template>
<button @click="increment">Count: {{ count }}</button>
</template>
```
### TypeScript Props & Emits
```vue
<script setup lang="ts">
interface Props {
server: VaultServer
}
const props = defineProps<Props>()
const emit = defineEmits<{
login: [credentials: VaultCredentials]
}>()
</script>
```
### Reactivity
- `ref()` - for primitive values (`ref(0)`, `ref('')`)
- `reactive()` - for objects (not used much, ref works for everything)
- `computed()` - for derived values
- `watch()` / `watchEffect()` - for side effects
## DaisyUI Components Used
### Buttons
```html
<button class="btn btn-primary">Primary</button>
<button class="btn btn-error">Danger</button>
<button class="btn btn-sm">Small</button>
<button class="btn loading">Loading</button>
```
### Cards
```html
<div class="card bg-base-100 shadow-xl">
<div class="card-body">
<h2 class="card-title">Title</h2>
<p>Content</p>
</div>
</div>
```
### Forms
```html
<div class="form-control">
<label class="label">
<span class="label-text">Label</span>
</label>
<input type="text" class="input input-bordered" />
</div>
```
### Alerts
```html
<div class="alert alert-info">
<svg>...</svg>
<span>Info message</span>
</div>
```
### Modal
```html
<div class="modal modal-open">
<div class="modal-box">
<!-- content -->
</div>
</div>
```
## Feature Comparison
| Feature | React Version | Vue Version | Status |
|---------|--------------|-------------|--------|
| Server Management | ✅ | ✅ | Identical |
| Multi-Auth Support | ✅ | ✅ | Identical |
| Login Verification | ✅ | ✅ | Identical |
| Mount Point Detection | ✅ | ✅ | Identical |
| Secret Reading | ✅ | ✅ | Identical |
| Recursive Search | ✅ | ✅ | Identical |
| Multi-Mount Search | ✅ | ✅ | Identical |
| Caching System | ✅ | ✅ | Identical |
| Settings Panel | ✅ | ✅ | Identical |
| KV v1/v2 Support | ✅ | ✅ | Identical |
| Dark/Light Mode | ✅ | ✅ | Improved (DaisyUI themes) |
| Responsive Design | ✅ | ✅ | Improved (Tailwind) |
## Benefits of Vue Version
### Code Quality
- ✅ **Less Code**: Vue templates are more concise than JSX
- ✅ **Better Separation**: Logic in `<script>`, template in `<template>`
- ✅ **Cleaner State**: No need for `setState`, just mutate `.value`
### Performance
- ✅ **Smaller Bundle**: Vue is ~30% smaller than React
- ✅ **Faster**: Vue's reactivity system is more efficient
- ✅ **Better Tree-Shaking**: Unused features are removed
### Developer Experience
- ✅ **Less Boilerplate**: No need for `useState`, `useEffect` everywhere
- ✅ **Better TypeScript**: Vue 3 has excellent TS support
- ✅ **Tailwind**: Utility-first CSS is faster than custom CSS
- ✅ **DaisyUI**: Pre-built components are beautiful and consistent
### Styling
- ✅ **Tailwind Utilities**: Faster development with utility classes
- ✅ **DaisyUI Components**: Beautiful, accessible components out of the box
- ✅ **Theme Support**: Easy dark/light mode switching
- ✅ **Less CSS**: ~500 lines of custom CSS → ~50 lines
## File Size Comparison
### React Version
- `node_modules/`: ~250 MB
- Bundle size: ~145 KB (gzipped)
### Vue Version (Estimated)
- `node_modules/`: ~180 MB
- Bundle size: ~95 KB (gzipped)
**30-35% smaller!**
## Browser Support
Same as before:
- Chrome/Edge 90+
- Firefox 90+
- Safari 14+
## Breaking Changes
**None!**
All functionality is preserved. The API is the same, features work identically, and all your data (servers, cache) persists in localStorage.
## Migration Notes
### What Developers Need to Know
If you're familiar with React:
1. **No JSX**: Use Vue templates instead
2. **No useState**: Use `ref()` instead
3. **No useEffect**: Use `onMounted()`, `watch()`, `watchEffect()`
4. **No props destructuring**: Use `props.propName`
5. **Events**: Emit events with `emit('eventName', data)`
6. **v-model**: Two-way binding (simpler than React controlled components)
7. **Directives**: `v-if`, `v-for`, `v-show`, `@click`, `:class`, etc.
### Example Conversion
**React:**
```tsx
const [count, setCount] = useState(0)
useEffect(() => {
console.log('Count changed:', count)
}, [count])
return (
<button onClick={() => setCount(count + 1)}>
{count}
</button>
)
```
**Vue:**
```vue
<script setup>
const count = ref(0)
watch(count, (newCount) => {
console.log('Count changed:', newCount)
})
</script>
<template>
<button @click="count++">
{{ count }}
</button>
</template>
```
## Theme Switching
DaisyUI supports multiple themes. To switch themes:
```html
<!-- In index.html -->
<html data-theme="dark"> <!-- or "light", "cupcake", etc. -->
```
Or dynamically:
```typescript
document.documentElement.setAttribute('data-theme', 'light')
```
Available themes: dark, light, cupcake, bumblebee, emerald, corporate, synthwave, retro, cyberpunk, valentine, halloween, garden, forest, aqua, lofi, pastel, fantasy, wireframe, black, luxury, dracula, cmyk, autumn, business, acid, lemonade, night, coffee, winter
## Next Steps
### Recommended Enhancements
1. **Add Vue Router** (if you want multiple pages)
2. **Add Pinia** (Vue's state management, like Redux)
3. **Add VueUse** (collection of useful composition utilities)
4. **Add animations** with Vue transitions
5. **PWA support** with Vite PWA plugin
### Optional Improvements
1. **Virtual scrolling** for large result lists
2. **Drag & drop** for organizing servers
3. **Keyboard shortcuts** with Vue composables
4. **Export/import** server configurations
5. **Secret editing** UI with forms
## Testing
To test the conversion:
1. `npm install`
2. `npm run dev`
3. Add a server (should work like before)
4. Login (mount points should be detected)
5. Read a secret
6. Try search (single path and all mounts)
7. Check settings panel
8. Verify cache statistics
Everything should work identically to the React version!
## Documentation
All previous documentation still applies:
- `README.md` - Updated for Vue
- `USAGE.md` - Same usage, new UI
- `KV_VERSIONS.md` - No changes
- `MOUNT_POINTS.md` - No changes
- `CORS_AND_CLIENT.md` - No changes
## Conclusion
✅ **Migration Complete!**
✅ **All features preserved**
✅ **Smaller bundle size**
✅ **Better performance**
✅ **Modern UI with Tailwind + DaisyUI**
✅ **Cleaner codebase**
The Vue version is production-ready! 🚀

View File

@ -1,6 +0,0 @@
def main():
print("Hello from browser-vault-gui!")
if __name__ == "__main__":
main()

View File

@ -1,7 +0,0 @@
[project]
name = "browser-vault-gui"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = []

View File

@ -13,13 +13,7 @@ const selectedServer = ref<VaultServer | null>(null)
const activeConnection = ref<VaultConnection | null>(null)
const { error } = useSweetAlert()
const { modalState, closePolicyModal, showPolicyModal } = usePolicyModal()
// Test function for debugging
const testPolicyModal = () => {
console.log('🔍 Testing policy modal')
showPolicyModal('secret/myapp/config', 'write', 'permission denied', 'Test Policy Modal')
}
const { modalState, closePolicyModal } = usePolicyModal()
// Load servers from localStorage on mount
onMounted(() => {
@ -116,11 +110,6 @@ const handleLogout = () => {
<!-- Main Content -->
<main class="flex-1 container mx-auto px-4 py-8">
<!-- Debug button -->
<div class="mb-4">
<button class="btn btn-sm btn-secondary" @click="testPolicyModal">🔍 Test Policy Modal</button>
</div>
<div v-if="!activeConnection" class="grid md:grid-cols-2 gap-8">
<!-- Server Selection -->
<div>