@pathscale/secure-local-storage-chacha20-poly1305
v1.0.1
Published
A secure localStorage wrapper using XChaCha20-Poly1305
Readme
Secure Local Storage XChaCha20-Poly1305
A secure, encrypted local storage library. This fork provides a drop-in replacement for localStorage with XChaCha20-Poly1305 authenticated encryption and type preservation.
🚀 Features
- 🔐 Automatic Encryption: All data is encrypted using XChaCha20-Poly1305
- 📝 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
- 🛡️ Authenticated Encryption: Stored values include an authentication tag
- ⚙️ 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
- Tampering: Stored ciphertext can be modified without the app noticing
- No type safety: Everything is stored as strings, losing original data types
The Solution
Secure Local Storage encrypts values before writing them to localStorage. For now, the package uses
a built-in 32-byte development key unless hashKey is provided as a raw 32-byte, base64, or hex key.
This is intended to be replaced by an auth-provided key after login.
📦 Installation
npm install @pathscale/secure-local-storage-chacha20-poly1305or
yarn add @pathscale/secure-local-storage-chacha20-poly1305🏃♂️ Quick Start
Basic Usage
import secureLocalStorage from '@pathscale/secure-local-storage-chacha20-poly1305';
// 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 '@pathscale/secure-local-storage-chacha20-poly1305';
// Create a custom instance with configuration
const customStorage = SecureLocalStorage.getInstance({
hashKey: '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef',
prefix: 'myapp_',
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: XChaCha20-Poly1305 authenticated encryption
- Implementation:
@stablelib/xchacha20poly1305 - Nonce: 24-byte random nonce per encrypted value
- Key: 32-byte raw key; accepts hex, base64, or raw 32-byte string input
- Temporary fallback: Built-in development key until auth provides a login-bound key
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 '@pathscale/secure-local-storage-chacha20-poly1305';
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 '@pathscale/secure-local-storage-chacha20-poly1305';
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 in the fork repository
- Create a new issue if needed
🔗 Related Projects
- StableLib - TypeScript cryptography packages
Forked from @jahidulsaeid/secure-local-storage and ported to XChaCha20-Poly1305.
