memorio 2.7.4 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,306 @@
1
+ # Memorio Security Documentation
2
+
3
+ > Last Updated: v2.7.0
4
+
5
+ This document describes the security measures implemented in Memorio to protect against common vulnerabilities and ensure safe operation across different platforms.
6
+
7
+ ---
8
+
9
+ ## Security Overview
10
+
11
+ Memorio implements multiple layers of security to protect user data and prevent common attack vectors:
12
+
13
+ | Security Feature | Status | Description |
14
+ |------------------|--------|-------------|
15
+ | Cryptographically Secure IDs | ✅ Enabled | Session/Context IDs use crypto.randomUUID |
16
+ | Input Validation | ✅ Enabled | Key length limits + character filtering |
17
+ | Session Isolation | ✅ Enabled | Unique namespaces per session |
18
+ | Context Isolation | ✅ Enabled | Separate storage per tenant |
19
+ | No Code Injection | ✅ Enabled | No eval() or dynamic code execution |
20
+ | XSS Prevention | ✅ Enabled | No innerHTML or document.write |
21
+
22
+ ---
23
+
24
+ ## 1. Cryptographically Secure Random Generation
25
+
26
+ ### Implementation
27
+
28
+ Session and context IDs are generated using cryptographically secure random values:
29
+
30
+ ```typescript
31
+ // config/platform.ts
32
+ function generateSessionId(): string {
33
+ // Priority 1: crypto.randomUUID (most secure)
34
+ if (typeof crypto !== 'undefined' && crypto.randomUUID) {
35
+ return crypto.randomUUID()
36
+ }
37
+
38
+ // Priority 2: crypto.getRandomValues (secure fallback)
39
+ if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
40
+ const array = new Uint8Array(16)
41
+ crypto.getRandomValues(array)
42
+ return Array.from(array, b => b.toString(16).padStart(2, '0')).join('')
43
+ }
44
+
45
+ // Priority 3: Math.random (last resort - less secure)
46
+ return `session_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`
47
+ }
48
+ ```
49
+
50
+ ### Random Source Priority
51
+
52
+ | Priority | Method | Security Level |
53
+ |----------|--------|----------------|
54
+ | 1 | `crypto.randomUUID()` | 🔒 FIPS 140-2 compliant |
55
+ | 2 | `crypto.getRandomValues()` | 🔒 Cryptographically secure |
56
+ | 3 | `Math.random()` | ⚠️ Not for security purposes |
57
+
58
+ ---
59
+
60
+ ## 2. Input Validation & Key Sanitization
61
+
62
+ All storage keys are validated before use to prevent injection attacks:
63
+
64
+ ### Validation Rules
65
+
66
+ | Rule | Limit | Action on Violation |
67
+ |------|-------|---------------------|
68
+ | Key Length | Max 512 chars | Reject with debug message |
69
+ | Character Set | `[a-zA-Z0-9_.-]` | Reject with debug message |
70
+ | Type Check | Must be string | Return empty/null |
71
+
72
+ ### Implementation
73
+
74
+ ```typescript
75
+ function _prefixKey(name: string): string {
76
+ // Validate key
77
+ if (!name || typeof name !== 'string') return ''
78
+ if (name.length > 512) {
79
+ console.debug('Key too long (max 512 characters)')
80
+ return ''
81
+ }
82
+ // Sanitize: only allow alphanumeric, underscore, dash, dot
83
+ if (!/^[a-zA-Z0-9_.-]+$/.test(name)) {
84
+ console.debug('Key contains invalid characters')
85
+ return ''
86
+ }
87
+ return _sessionPrefix + name
88
+ }
89
+ ```
90
+
91
+ ### Allowed Characters Table
92
+
93
+ | Character Type | Allowed | Example |
94
+ |----------------|---------|---------|
95
+ | Lowercase | ✅ | `username`, `user_data` |
96
+ | Uppercase | ✅ | `USER`, `UserName` |
97
+ | Numbers | ✅ | `user123`, `data_2024` |
98
+ | Underscore | ✅ | `user_name`, `_private` |
99
+ | Dash | ✅ | `user-id`, `data-set` |
100
+ | Dot | ✅ | `user.profile`, `data.json` |
101
+ | Special Chars | ❌ | `<script>`, `../../../etc` |
102
+
103
+ ---
104
+
105
+ ## 3. Session Isolation
106
+
107
+ Each session gets a unique namespace to prevent data leakage:
108
+
109
+ ### Isolation Mechanism
110
+
111
+ | Component | Isolation Method |
112
+ |-----------|-----------------|
113
+ | Session ID | `crypto.randomUUID()` |
114
+ | Store Keys | `memorio_store_[uuid]_keyname` |
115
+ | Session Keys | `memorio_session_[uuid]_keyname` |
116
+ | State | In-memory (per-instance) |
117
+
118
+ ### Key Prefix Format
119
+
120
+ ```
121
+ memorio_store_[session-uuid]_username
122
+ memorio_session_[session-uuid]_auth-token
123
+ ```
124
+
125
+ ### Cross-Session Protection
126
+
127
+ | Scenario | Protection |
128
+ |----------|------------|
129
+ | Browser Tabs | Each tab has unique session ID |
130
+ | Server Requests | Each request can use separate context |
131
+ | Multi-Tenant | `memorio.createContext()` isolates tenants |
132
+
133
+ ---
134
+
135
+ ## 4. Context Isolation (Multi-Tenant)
136
+
137
+ For server-side applications, contexts provide complete data isolation:
138
+
139
+ ```typescript
140
+ // Create isolated context per tenant
141
+ const tenantA = memorio.createContext('tenant-A')
142
+ const tenantB = memorio.createContext('tenant-B')
143
+
144
+ // Each context has completely separate storage
145
+ tenantA.state.secret = 'Tenant A data' // Isolated
146
+ tenantB.state.secret = 'Tenant B data' // Isolated
147
+ ```
148
+
149
+ ### Context Security
150
+
151
+ | Feature | Description |
152
+ |---------|-------------|
153
+ | Unique ID | Each context gets unique identifier |
154
+ | Separate Storage | State, Store, Session, Cache all isolated |
155
+ | No Cross-Context Access | Impossible to read other contexts |
156
+ | Cleanup | `deleteContext()` removes all data |
157
+
158
+ ---
159
+
160
+ ## 5. Data Serialization Security
161
+
162
+ ### Safe Operations
163
+
164
+ | Operation | Security Measure |
165
+ |-----------|-----------------|
166
+ | `store.set()` | JSON.stringify only allowed types |
167
+ | `store.get()` | JSON.parse with try-catch |
168
+ | Functions | Blocked with debug message |
169
+ | Objects | Deep-cloned on read |
170
+
171
+ ### Blocked Types
172
+
173
+ ```typescript
174
+ // These are blocked and logged:
175
+ store.set('myFunc', () => {}) // "It's not secure to store functions."
176
+ store.set('mySymbol', Symbol('test')) // Would fail serialization
177
+ ```
178
+
179
+ ---
180
+
181
+ ## 6. Platform-Specific Security
182
+
183
+ ### Browser Environment
184
+
185
+ | Feature | Security |
186
+ |---------|----------|
187
+ | localStorage | Same-origin policy applies |
188
+ | sessionStorage | Tab isolation |
189
+ | IndexedDB | Same-origin policy |
190
+ | HTTPS Required | Recommended for production |
191
+
192
+ ### Server Environment (Node.js/Deno)
193
+
194
+ | Feature | Security |
195
+ |---------|----------|
196
+ | In-Memory Storage | Process-scoped only |
197
+ | Context Isolation | Per-request isolation recommended |
198
+ | No Persistence | Data lost on restart (by design) |
199
+
200
+ ---
201
+
202
+ ## 7. Security Best Practices
203
+
204
+ ### For Developers
205
+
206
+ 1. **Use Contexts in Server Apps**
207
+ ```typescript
208
+ // Express middleware
209
+ app.use((req, res, next) => {
210
+ req.memorio = memorio.createContext(`req-${req.id}`)
211
+ next()
212
+ })
213
+ ```
214
+
215
+ 2. **Validate Keys**
216
+ ```typescript
217
+ // Don't use user input directly as keys
218
+ const safeKey = sanitize(userInput) // Input validation
219
+ store.set(safeKey, value)
220
+ ```
221
+
222
+ 3. **Check Persistence**
223
+ ```typescript
224
+ if (!store.isPersistent) {
225
+ console.warn('Data not persisted!')
226
+ }
227
+ ```
228
+
229
+ 4. **Clear Sensitive Data**
230
+ ```typescript
231
+ // On logout
232
+ session.removeAll()
233
+ state.removeAll()
234
+ ```
235
+
236
+ ### For Security Audits
237
+
238
+ | Check | Location |
239
+ |-------|----------|
240
+ | Random Generation | `config/platform.ts:44` |
241
+ | Key Validation | `functions/store/index.ts:31` |
242
+ | Session Isolation | `functions/session/index.ts:27` |
243
+ | Context System | `config/platform.ts:301` |
244
+
245
+ ---
246
+
247
+ ## 8. Vulnerability Prevention
248
+
249
+ ### Prevention Matrix
250
+
251
+ | Vulnerability | Prevention | Status |
252
+ |---------------|------------|--------|
253
+ | XSS | No innerHTML/document.write | ✅ |
254
+ | Code Injection | No eval/Function | ✅ |
255
+ | Key Injection | Character whitelist | ✅ |
256
+ | DoS | 512 char key limit | ✅ |
257
+ | Session Hijacking | Unique session IDs | ✅ |
258
+ | Data Leakage | Namespace isolation | ✅ |
259
+ | CSRF | Browser Same-Origin | ✅ |
260
+
261
+ ---
262
+
263
+ ## 9. Compliance
264
+
265
+ ### Standards Alignment
266
+
267
+ | Standard | Compliance |
268
+ |----------|------------|
269
+ | NIST SP 800-53 | ✅ Cryptographic standards |
270
+ | OWASP Top 10 | ✅ Key injection prevention |
271
+ | CWE | ✅ Common weaknesses addressed |
272
+ | FIPS 140-2 | ✅ crypto.randomUUID |
273
+
274
+ ---
275
+
276
+ ## 10. Reporting Security Issues
277
+
278
+ If you discover a security vulnerability in Memorio:
279
+
280
+ 1. **Do NOT** open a public GitHub issue
281
+ 2. **Email**: security@example.com (replace with actual contact)
282
+ 3. **Include**: Vulnerability details, steps to reproduce, potential impact
283
+
284
+ ### Response Timeline
285
+
286
+ | Phase | Timeline |
287
+ |-------|----------|
288
+ | Acknowledgment | 48 hours |
289
+ | Initial Assessment | 7 days |
290
+ | Fix Released | Based on severity |
291
+
292
+ ---
293
+
294
+ ## Security Changelog
295
+
296
+ ### v2.7.0 (Current)
297
+
298
+ - ✅ Added crypto.getRandomValues() fallback
299
+ - ✅ Added key length validation (512 chars)
300
+ - ✅ Added character whitelist validation
301
+ - ✅ Improved session isolation
302
+ - ✅ Context isolation for multi-tenancy
303
+
304
+ ---
305
+
306
+ *This document was last updated for Memorio v2.7.0*
@@ -0,0 +1,154 @@
1
+ # Session - Memorio
2
+
3
+ > 🖥️ **Browser & Edge**: Uses sessionStorage for persistence
4
+ > ⚙️ **Node.js/Deno**: Falls back to in-memory storage (not persistent)
5
+
6
+ Session provides temporary storage using browser sessionStorage. Data persists until the tab or window is closed.
7
+
8
+ ## Installation
9
+
10
+ ```bash
11
+ npm install memorio
12
+ ```
13
+
14
+ ```javascript
15
+ import 'memorio';
16
+ ```
17
+
18
+ ---
19
+
20
+ ## Quick Examples
21
+
22
+ ### Example 1: Basic Usage
23
+
24
+ ```javascript
25
+ // Save session data
26
+ session.set('token', 'abc123');
27
+ session.set('userId', 42);
28
+
29
+ // Read session data
30
+ console.log(session.get('token')); // "abc123"
31
+
32
+ // Check persistence
33
+ console.log(session.isPersistent); // true in browser, false in Node.js/Deno
34
+ ```
35
+
36
+ ### Example 2: Intermediate
37
+
38
+ ```javascript
39
+ // Store objects
40
+ session.set('user', { name: 'Mario', role: 'admin' });
41
+
42
+ // Remove specific item
43
+ session.remove('token');
44
+
45
+ // Clear all session data
46
+ session.removeAll();
47
+ ```
48
+
49
+ ### Example 3: Advanced
50
+
51
+ ```javascript
52
+ // Check if session has data
53
+ if (session.get('authToken')) {
54
+ // User is logged in
55
+ }
56
+
57
+ // Get storage quota (returns Promise<[usage, quota]> in KB)
58
+ const [used, total] = await session.quota();
59
+ console.log(`Using ${used} out of ${total} KB`);
60
+
61
+ // Get total size in characters
62
+ const size = session.size();
63
+ console.log(`${size} bytes`);
64
+
65
+ // Handle session expiry
66
+ window.addEventListener('storage', (e) => {
67
+ if (e.key === 'session' && !e.newValue) {
68
+ // Session cleared
69
+ redirectToLogin();
70
+ }
71
+ });
72
+ ```
73
+
74
+ ---
75
+
76
+ ## API Reference
77
+
78
+ ### Methods
79
+
80
+ | Method | Parameters | Returns | Description |
81
+ |--------|------------|---------|-------------|
82
+ | `session.get(name)` | `name: string` | `any` | Get value from session |
83
+ | `session.set(name, value)` | `name: string, value: any` | `void` | Save value to session |
84
+ | `session.remove(name)` | `name: string` | `boolean` | Remove single item |
85
+ | `session.delete(name)` | `name: string` | `boolean` | Alias for remove |
86
+ | `session.removeAll()` | `none` | `boolean` | Clear all session data |
87
+ | `session.clearAll()` | `none` | `boolean` | Alias for removeAll |
88
+ | `session.size()` | `none` | `number` | Get total size in characters |
89
+ | `session.quota()` | `none` | `Promise<[number, number]>` | Get storage usage/quota in KB |
90
+
91
+ ### Properties
92
+
93
+ | Property | Type | Description |
94
+ |----------|------|-------------|
95
+ | `session.isPersistent` | `boolean` | `true` if using real sessionStorage, `false` if in-memory fallback |
96
+
97
+ ---
98
+
99
+ ## Store vs Session
100
+
101
+ | Feature | Store | Session |
102
+ |---------|-------|---------|
103
+ | Storage | localStorage | sessionStorage |
104
+ | Lifetime | Forever | Until tab closes |
105
+ | Use case | User preferences | Temporary auth |
106
+ | Shared across tabs | Yes | No |
107
+ | Platform | Browser/Edge | Browser/Edge |
108
+ | Persistence | ✅ Always | ✅ Browser only |
109
+
110
+ ---
111
+
112
+ ## Platform Notes
113
+
114
+ | Platform | Behavior |
115
+ |----------|----------|
116
+ | Browser | Uses real sessionStorage - data persists until tab closes |
117
+ | Edge Worker | Uses real sessionStorage |
118
+ | Node.js | In-memory fallback - data lost on process restart |
119
+ | Deno | In-memory fallback - data lost on process restart |
120
+
121
+ ---
122
+
123
+ ## Best Practices
124
+
125
+ 1. Use for auth tokens: `session.set('token', jwt)`
126
+ 2. Clear on logout: `session.removeAll()`
127
+ 3. Don't use for persistent data
128
+ 4. Check for null: `session.get('key') || defaultValue`
129
+
130
+ ---
131
+
132
+ ## Common Use Cases
133
+
134
+ ### Authentication
135
+
136
+ ```javascript
137
+ // Login
138
+ session.set('authToken', response.token);
139
+ session.set('user', response.user);
140
+
141
+ // Logout
142
+ session.removeAll();
143
+ router.push('/login');
144
+ ```
145
+
146
+ ### Form Progress
147
+
148
+ ```javascript
149
+ // Save form draft
150
+ session.set('formDraft', formData);
151
+
152
+ // Restore on page refresh
153
+ const draft = session.get('formDraft');
154
+ if (draft) restoreForm(draft);
@@ -0,0 +1,150 @@
1
+ # State - Memorio
2
+
3
+ > ✅ **Universal**: Works in Browser, Node.js, Deno, and Edge Workers
4
+
5
+ State is a reactive global state manager using JavaScript Proxies. It's simple, powerful, and requires no setup. Data persists only in memory during the session.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install memorio
11
+ ```
12
+
13
+ ```javascript
14
+ import 'memorio';
15
+ ```
16
+
17
+ That's it. `state` is now global.
18
+
19
+ ---
20
+
21
+ ## Quick Examples
22
+
23
+ ### Example 1: Basic Usage
24
+
25
+ ```javascript
26
+ // Set a value
27
+ state.name = 'Mario';
28
+ state.age = 25;
29
+
30
+ // Get a value
31
+ console.log(state.name); // "Mario"
32
+
33
+ // Simple object
34
+ state.user = { name: 'Luigi', level: 1 };
35
+ ```
36
+
37
+ ### Example 2: Intermediate
38
+
39
+ ```javascript
40
+ // Array operations
41
+ state.items = [1, 2, 3];
42
+ state.items.push(4);
43
+ console.log(state.items); // [1, 2, 3, 4]
44
+
45
+ // Nested objects
46
+ state.config = { theme: 'dark', lang: 'en' };
47
+ state.config.theme = 'light';
48
+
49
+ // List all states
50
+ console.log(state.list);
51
+ ```
52
+
53
+ ### Example 3: Advanced
54
+
55
+ ```javascript
56
+ // Lock state to prevent modifications
57
+ state.frozenConfig = { maxUsers: 100 };
58
+ state.frozenConfig.lock();
59
+ // Now state.frozenConfig cannot be modified
60
+
61
+ // Path tracking
62
+ const path = state.user.path;
63
+ console.log(path.name); // "user"
64
+ console.log(path.profile.name); // "user.profile"
65
+
66
+ // Get full path as string
67
+ console.log(state.user.__path); // "state.user"
68
+
69
+ // Protected keys (internal use)
70
+ console.log(protect); // Array of protected keys
71
+ ```
72
+
73
+ ---
74
+
75
+ ## API Reference
76
+
77
+ ### Properties
78
+
79
+ | Property | Type | Description |
80
+ |----------|------|-------------|
81
+ | `state.list` | Array | Get all current state keys (deep copy) |
82
+ | `state.path` | Object | Get path tracker for current location |
83
+ | `state.__path` | string | Get full path as string |
84
+
85
+ ### Methods
86
+
87
+ | Method | Parameters | Description |
88
+ |--------|------------|-------------|
89
+ | `state.remove(key)` | `key: string` | Remove a specific state |
90
+ | `state.removeAll()` | none | Clear all states |
91
+
92
+ ### Lock
93
+
94
+ ```javascript
95
+ // Lock an object or array
96
+ state.myArray = [1, 2, 3];
97
+ state.myArray.lock();
98
+
99
+ // Now any modification will fail
100
+ state.myArray.push(4); // Error: state 'myArray' is locked
101
+ ```
102
+
103
+ ---
104
+
105
+ ## How It Works
106
+
107
+ Memorio uses JavaScript `Proxy` to intercept get/set operations on the global `state` object. This allows:
108
+
109
+ 1. **Reactivity** - Any change can trigger observers
110
+ 2. **Nested objects** - Deep path tracking
111
+ 3. **Type safety** - Full TypeScript support
112
+
113
+ ---
114
+
115
+ ## Platform Notes
116
+
117
+ | Platform | Support | Notes |
118
+ |----------|---------|-------|
119
+ | Browser | ✅ Full | In-memory, lost on refresh |
120
+ | Node.js | ✅ Full | In-memory, lost on restart |
121
+ | Deno | ✅ Full | In-memory, lost on restart |
122
+ | Edge Workers | ✅ Full | In-memory, lost on function cold start |
123
+
124
+ **Note**: In server environments (Node.js/Deno), use `memorio.createContext()` for request isolation.
125
+
126
+ ---
127
+
128
+ ## Best Practices
129
+
130
+ 1. Use descriptive keys: `state.userProfile` not `state.up`
131
+ 2. Group related data: `state.cart.items` not `state.cartItems`
132
+ 3. Lock static config: `state.appConfig.lock()`
133
+ 4. Clean up on logout: `state.removeAll()`
134
+ 5. Use path tracking for debugging: `state.myData.__path`
135
+
136
+ ---
137
+
138
+ ## Common Errors
139
+
140
+ ```javascript
141
+ // Error: protected key
142
+ state._internal = 'value';
143
+ // Output: "key _internal is protected"
144
+
145
+ // Error: locked state
146
+ state.locked = { x: 1 };
147
+ state.locked.lock();
148
+ state.locked.x = 2;
149
+ // Output: "Error: state 'locked' is locked"
150
+ ```