@jahidulsaeid/secure-local-storage
v1.0.2
Published
A secure, encrypted local storage library with browser fingerprinting for enhanced security
Maintainers
Readme
🔒 Secure Local Storage
A secure, encrypted local storage library with browser fingerprinting for enhanced security. This library provides a drop-in replacement for localStorage with automatic encryption, type preservation, and browser-specific security keys.
🚀 Features
- 🔐 Automatic Encryption: All data is encrypted using AES encryption with browser-specific keys
- 🔍 Browser Fingerprinting: Generates unique keys based on browser characteristics
- 📝 Type Preservation: Maintains original data types (string, number, boolean, object)
- 🎯 Framework Agnostic: Works with React, Vue, Angular, Vite, Next.js, and vanilla JavaScript
- 💾 Memory Caching: Singleton pattern with in-memory cache for performance
- 🛡️ Secure by Default: Each browser generates its own encryption key
- ⚙️ Configurable: Extensive configuration options and environment variable support
- 📦 TypeScript Ready: Full TypeScript support with comprehensive type definitions
- 🚀 Production Ready: Thoroughly tested and optimized for performance
🤔 Why Secure Local Storage?
The Problem with Regular localStorage
Regular localStorage stores data as plain text, making it vulnerable to:
- Data theft: Anyone with device access can read your stored data
- Cross-browser attacks: Encrypted data from one browser can be copied to another
- No type safety: Everything is stored as strings, losing original data types
The Solution
Secure Local Storage generates a unique encryption key for each browser using:
- Browser fingerprinting (10+ unique identifiers)
- User-specific hash keys
- Environment-specific configuration
This ensures that data encrypted in one browser cannot be decrypted in another, even if the encrypted data is copied.
📦 Installation
npm install @jahidulsaeid/secure-local-storageor
yarn add @jahidulsaeid/secure-local-storage🏃♂️ Quick Start
Basic Usage
import secureLocalStorage from '@jahidulsaeid/secure-local-storage';
// Store different data types
secureLocalStorage.setItem('user', {
name: 'John Doe',
age: 30,
active: true
});
secureLocalStorage.setItem('count', 42);
secureLocalStorage.setItem('enabled', true);
secureLocalStorage.setItem('message', 'Hello, World!');
// Retrieve data (maintains original types)
const user = secureLocalStorage.getItem('user'); // Returns object
const count = secureLocalStorage.getItem('count'); // Returns number
const enabled = secureLocalStorage.getItem('enabled'); // Returns boolean
const message = secureLocalStorage.getItem('message'); // Returns string
// Remove items
secureLocalStorage.removeItem('user');
// Clear all secure storage
secureLocalStorage.clear();
// Get all keys
const keys = secureLocalStorage.keys(); // Returns string[]
// Get storage length
const length = secureLocalStorage.length(); // Returns numberAdvanced Usage
import { SecureLocalStorage } from '@jahidulsaeid/secure-local-storage';
// Create a custom instance with configuration
const customStorage = SecureLocalStorage.getInstance({
hashKey: 'my-custom-key',
prefix: 'myapp_',
disabledKeys: ['Canvas', 'Fonts'], // Disable specific fingerprint properties
debug: true
});
// Use the custom instance
customStorage.setItem('data', { custom: true });⚙️ Configuration
Environment Variables
Secure Local Storage supports multiple frameworks through environment variables:
React
REACT_APP_SECURE_LOCAL_STORAGE_HASH_KEY=your-secret-key
REACT_APP_SECURE_LOCAL_STORAGE_PREFIX=myapp_
REACT_APP_SECURE_LOCAL_STORAGE_DISABLED_KEYS=Canvas|FontsVite
VITE_SECURE_LOCAL_STORAGE_HASH_KEY=your-secret-key
VITE_SECURE_LOCAL_STORAGE_PREFIX=myapp_
VITE_SECURE_LOCAL_STORAGE_DISABLED_KEYS=Canvas|FontsNext.js
NEXT_PUBLIC_SECURE_LOCAL_STORAGE_HASH_KEY=your-secret-key
NEXT_PUBLIC_SECURE_LOCAL_STORAGE_PREFIX=myapp_
NEXT_PUBLIC_SECURE_LOCAL_STORAGE_DISABLED_KEYS=Canvas|FontsGeneric/Node.js
SECURE_LOCAL_STORAGE_HASH_KEY=your-secret-key
SECURE_LOCAL_STORAGE_PREFIX=myapp_
SECURE_LOCAL_STORAGE_DISABLED_KEYS=Canvas|FontsVite Configuration
For Vite projects, you need to define process.env in your vite.config.ts:
import { defineConfig } from 'vite'
export default defineConfig({
define: {
"process.env": {
SECURE_LOCAL_STORAGE_HASH_KEY: JSON.stringify(process.env.VITE_SECURE_LOCAL_STORAGE_HASH_KEY),
// Add other environment variables as needed
},
},
})Configuration Options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| hashKey | string | 'secure-local-storage-default-key' | Custom encryption key |
| prefix | string | 'sls_' | Storage key prefix |
| disabledKeys | FingerprintProperty[] | [] | Disabled fingerprint properties |
| debug | boolean | false | Enable debug logging |
Fingerprint Properties
You can disable specific browser fingerprint properties:
| Property | Description |
|----------|-------------|
| UserAgent | Browser user agent string |
| ScreenPrint | Screen dimensions and color depth |
| Plugins | Installed browser plugins |
| Fonts | Available system fonts |
| LocalStorage | localStorage availability |
| SessionStorage | sessionStorage availability |
| TimeZone | System timezone |
| Language | Browser language |
| SystemLanguage | System language |
| Cookie | Cookie support |
| Canvas | Canvas fingerprint |
| Hostname | Current hostname |
Note: Disabling properties reduces the uniqueness of the browser fingerprint, potentially making encryption less secure.
🔧 API Reference
Methods
setItem(key: string, value: StorageValue): void
Stores a value in secure local storage.
secureLocalStorage.setItem('user', { name: 'John', age: 30 });getItem(key: string): StorageValue
Retrieves a value from secure local storage. Returns null if the key doesn't exist.
const user = secureLocalStorage.getItem('user');removeItem(key: string): void
Removes a specific item from secure local storage.
secureLocalStorage.removeItem('user');clear(): void
Removes all items from secure local storage.
secureLocalStorage.clear();keys(): string[]
Returns an array of all keys in secure local storage.
const allKeys = secureLocalStorage.keys();length(): number
Returns the number of items in secure local storage.
const itemCount = secureLocalStorage.length();Types
type StorageValue = string | number | boolean | object | null;
interface SecureStorageConfig {
hashKey?: string;
prefix?: string;
disabledKeys?: FingerprintProperty[];
debug?: boolean;
}
type FingerprintProperty =
| 'UserAgent' | 'ScreenPrint' | 'Plugins' | 'Fonts'
| 'LocalStorage' | 'SessionStorage' | 'TimeZone' | 'Language'
| 'SystemLanguage' | 'Cookie' | 'Canvas' | 'Hostname';🔒 Security Features
Encryption Details
- Algorithm: AES encryption with PBKDF2 key derivation
- Key Generation: Combines user hash key with browser fingerprint
- Salt: Uses a fixed salt for consistent key generation
- Iterations: 1000 PBKDF2 iterations for key strengthening
Browser Fingerprinting
The library generates a unique fingerprint using:
- User agent string
- Screen dimensions and color depth
- Installed plugins
- Available fonts (canvas-based detection)
- Storage capabilities
- Timezone and language settings
- Canvas fingerprint
- Current hostname
Data Protection
- Each encrypted item includes metadata (type, timestamp, version)
- Type information is preserved and restored
- Memory cache prevents repeated decryption operations
- Automatic validation of encrypted data integrity
📚 Examples
React Example
import React, { useState, useEffect } from 'react';
import secureLocalStorage from '@jahidulsaeid/secure-local-storage';
const UserProfile: React.FC = () => {
const [user, setUser] = useState(null);
useEffect(() => {
// Load user from secure storage
const savedUser = secureLocalStorage.getItem('user');
if (savedUser) {
setUser(savedUser);
}
}, []);
const saveUser = (userData: any) => {
secureLocalStorage.setItem('user', userData);
setUser(userData);
};
const logout = () => {
secureLocalStorage.removeItem('user');
setUser(null);
};
return (
<div>
{user ? (
<div>
<h1>Welcome, {user.name}!</h1>
<button onClick={logout}>Logout</button>
</div>
) : (
<button onClick={() => saveUser({ name: 'John', id: 1 })}>
Login
</button>
)}
</div>
);
};Vue Example
<template>
<div>
<h1 v-if="user">Welcome, {{ user.name }}!</h1>
<button @click="toggleUser">
{{ user ? 'Logout' : 'Login' }}
</button>
</div>
</template>
<script>
import secureLocalStorage from '@jahidulsaeid/secure-local-storage';
export default {
data() {
return {
user: null
};
},
mounted() {
this.user = secureLocalStorage.getItem('user');
},
methods: {
toggleUser() {
if (this.user) {
secureLocalStorage.removeItem('user');
this.user = null;
} else {
const userData = { name: 'John', id: 1 };
secureLocalStorage.setItem('user', userData);
this.user = userData;
}
}
}
};
</script>🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
Please read our Contributing Guide for detailed information on:
- Setting up the development environment
- Running tests locally
- Code style guidelines
- Submitting pull requests
- Development workflow
Development Setup
- Clone the repository
- Install dependencies:
npm install - Build the project:
npm run build - Run linting:
npm run lint - Test locally in a browser with the built files
For detailed development instructions, see CONTRIBUTING.md.
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙋♂️ Support
If you have any questions or issues, please:
- Check the documentation
- Search existing issues
- Create a new issue
🔗 Related Projects
- crypto-js - Cryptographic utilities
- fingerprintjs - Browser fingerprinting
Made with ❤️ by jahidulsaeid
