hola-server 1.0.11 → 2.0.1
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.
- package/README.md +196 -1
- package/core/array.js +79 -142
- package/core/bash.js +208 -259
- package/core/chart.js +26 -16
- package/core/cron.js +14 -3
- package/core/date.js +15 -44
- package/core/encrypt.js +19 -9
- package/core/file.js +42 -29
- package/core/lhs.js +32 -6
- package/core/meta.js +213 -289
- package/core/msg.js +20 -7
- package/core/number.js +105 -103
- package/core/obj.js +15 -12
- package/core/random.js +9 -6
- package/core/role.js +69 -77
- package/core/thread.js +12 -2
- package/core/type.js +300 -261
- package/core/url.js +20 -12
- package/core/validate.js +29 -26
- package/db/db.js +297 -227
- package/db/entity.js +631 -963
- package/db/gridfs.js +120 -166
- package/design/add_default_field_attr.md +56 -0
- package/http/context.js +22 -8
- package/http/cors.js +25 -8
- package/http/error.js +27 -9
- package/http/express.js +70 -41
- package/http/params.js +70 -42
- package/http/router.js +51 -40
- package/http/session.js +59 -36
- package/index.js +85 -9
- package/package.json +2 -2
- package/router/clone.js +28 -36
- package/router/create.js +21 -26
- package/router/delete.js +24 -28
- package/router/read.js +137 -123
- package/router/update.js +38 -56
- package/setting.js +22 -6
- package/skills/array.md +155 -0
- package/skills/bash.md +91 -0
- package/skills/chart.md +54 -0
- package/skills/code.md +422 -0
- package/skills/context.md +177 -0
- package/skills/date.md +58 -0
- package/skills/express.md +255 -0
- package/skills/file.md +60 -0
- package/skills/lhs.md +54 -0
- package/skills/meta.md +1023 -0
- package/skills/msg.md +30 -0
- package/skills/number.md +88 -0
- package/skills/obj.md +36 -0
- package/skills/params.md +206 -0
- package/skills/random.md +22 -0
- package/skills/role.md +59 -0
- package/skills/session.md +281 -0
- package/skills/storage.md +743 -0
- package/skills/thread.md +22 -0
- package/skills/type.md +547 -0
- package/skills/url.md +34 -0
- package/skills/validate.md +48 -0
- package/test/cleanup/close-db.js +5 -0
- package/test/core/array.js +226 -0
- package/test/core/chart.js +51 -0
- package/test/core/file.js +59 -0
- package/test/core/lhs.js +44 -0
- package/test/core/number.js +167 -12
- package/test/core/obj.js +47 -0
- package/test/core/random.js +24 -0
- package/test/core/thread.js +20 -0
- package/test/core/type.js +216 -0
- package/test/core/validate.js +67 -0
- package/test/db/db-ops.js +99 -0
- package/test/db/pipe_test.txt +0 -0
- package/test/db/test_case_design.md +528 -0
- package/test/db/test_db_class.js +613 -0
- package/test/db/test_entity_class.js +414 -0
- package/test/db/test_gridfs_class.js +234 -0
- package/test/entity/create.js +1 -1
- package/test/entity/delete-mixed.js +156 -0
- package/test/entity/ref-filter.js +63 -0
- package/tool/gen_i18n.js +55 -21
- package/test/crud/router.js +0 -99
- package/test/router/user.js +0 -17
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
# Session Management Skill
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `hola-server/http/session.js` module provides session management utilities using `express-session` with MongoDB storage. It includes helpers for accessing session data and checking ownership permissions.
|
|
6
|
+
|
|
7
|
+
## Importing
|
|
8
|
+
|
|
9
|
+
```javascript
|
|
10
|
+
const {
|
|
11
|
+
init_session,
|
|
12
|
+
get_session_user_id,
|
|
13
|
+
get_session_user_groups,
|
|
14
|
+
is_owner
|
|
15
|
+
} = require("hola-server/http/session");
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## API Reference
|
|
19
|
+
|
|
20
|
+
### 1. Session Initialization
|
|
21
|
+
|
|
22
|
+
#### `init_session(app)`
|
|
23
|
+
Initializes session middleware with MongoDB storage.
|
|
24
|
+
|
|
25
|
+
**Called automatically** by `init_express_server()`. You typically don't call this directly.
|
|
26
|
+
|
|
27
|
+
**Configuration:**
|
|
28
|
+
```javascript
|
|
29
|
+
// settings.json
|
|
30
|
+
{
|
|
31
|
+
"server": {
|
|
32
|
+
"keep_session": true,
|
|
33
|
+
"session": {
|
|
34
|
+
"secret": "your-secret-key-change-in-production",
|
|
35
|
+
"cookie_max_age": 86400000 // 24 hours in ms
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"mongo": {
|
|
39
|
+
"url": "mongodb://localhost:27017/mydb"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. Session Access
|
|
45
|
+
|
|
46
|
+
#### `get_session_user_id(req)`
|
|
47
|
+
Gets the current user ID from session.
|
|
48
|
+
|
|
49
|
+
**Returns:** `string|null` - User ID or null if not logged in
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
const { NO_SESSION } = require("hola-server/http/code");
|
|
53
|
+
|
|
54
|
+
const user_id = get_session_user_id(req);
|
|
55
|
+
if (!user_id) {
|
|
56
|
+
return res.json({ code: NO_SESSION });
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
#### `get_session_user_groups(req)`
|
|
61
|
+
Gets the current user's group IDs from session.
|
|
62
|
+
|
|
63
|
+
**Returns:** `string[]|null` - Array of group IDs or null
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
const { NO_RIGHTS } = require("hola-server/http/code");
|
|
67
|
+
|
|
68
|
+
const groups = get_session_user_groups(req);
|
|
69
|
+
if (!groups || !groups.includes("admin")) {
|
|
70
|
+
return res.json({ code: NO_RIGHTS });
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 3. Ownership Checking
|
|
75
|
+
|
|
76
|
+
#### `is_owner(req, meta, entity, query)`
|
|
77
|
+
Checks if the current user owns the entity being accessed.
|
|
78
|
+
|
|
79
|
+
**Parameters:**
|
|
80
|
+
- `req` (Object): Express request
|
|
81
|
+
- `meta` (Object): Entity meta definition
|
|
82
|
+
- `entity` (Entity): Entity instance
|
|
83
|
+
- `query` (Object): MongoDB query for the entity
|
|
84
|
+
|
|
85
|
+
**Returns:** `Promise<boolean>` - True if user is owner or root user
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
const { NO_RIGHTS } = require("hola-server/http/code");
|
|
89
|
+
|
|
90
|
+
const can_access = await is_owner(req, meta, entity, { _id: req.params.id });
|
|
91
|
+
if (!can_access) {
|
|
92
|
+
return res.json({ code: NO_RIGHTS });
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Logic:**
|
|
97
|
+
1. Returns `true` if user is root (via `is_root_user()`)
|
|
98
|
+
2. Returns `true` if meta has no `user_field` defined
|
|
99
|
+
3. Otherwise, checks if entity's `user_field` matches current user ID
|
|
100
|
+
|
|
101
|
+
## Session Structure
|
|
102
|
+
|
|
103
|
+
The framework expects sessions to contain:
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
req.session = {
|
|
107
|
+
user: {
|
|
108
|
+
id: "507f1f77bcf86cd799439011", // User ObjectId
|
|
109
|
+
name: "John Doe",
|
|
110
|
+
role: "admin",
|
|
111
|
+
// ... other user fields
|
|
112
|
+
},
|
|
113
|
+
group: ["group_id_1", "group_id_2"] // Optional: user's group memberships
|
|
114
|
+
};
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Usage Patterns
|
|
118
|
+
|
|
119
|
+
### Pattern 1: Login Flow
|
|
120
|
+
|
|
121
|
+
```javascript
|
|
122
|
+
const { ERROR, SUCCESS } = require("hola-server/http/code");
|
|
123
|
+
|
|
124
|
+
router.post("/login", async (req, res) => {
|
|
125
|
+
const { username, password } = req.body;
|
|
126
|
+
|
|
127
|
+
// Authenticate user
|
|
128
|
+
const user = await authenticate(username, password);
|
|
129
|
+
if (!user) {
|
|
130
|
+
return res.json({ code: ERROR, err: "Invalid credentials" });
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Set session
|
|
134
|
+
req.session.user = {
|
|
135
|
+
id: user._id,
|
|
136
|
+
name: user.name,
|
|
137
|
+
email: user.email,
|
|
138
|
+
role: user.role
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
if (user.groups) {
|
|
142
|
+
req.session.group = user.groups;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return res.json({ code: SUCCESS, user });
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Pattern 2: Logout
|
|
150
|
+
|
|
151
|
+
```javascript
|
|
152
|
+
const { ERROR, SUCCESS } = require("hola-server/http/code");
|
|
153
|
+
|
|
154
|
+
router.post("/logout", (req, res) => {
|
|
155
|
+
req.session.destroy((err) => {
|
|
156
|
+
if (err) {
|
|
157
|
+
return res.json({ code: ERROR, err: "Logout failed" });
|
|
158
|
+
}
|
|
159
|
+
res.json({ code: SUCCESS });
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Pattern 3: Protected Routes
|
|
165
|
+
|
|
166
|
+
```javascript
|
|
167
|
+
const { NO_SESSION, SUCCESS } = require("hola-server/http/code");
|
|
168
|
+
|
|
169
|
+
router.get("/profile", async (req, res) => {
|
|
170
|
+
const user_id = get_session_user_id(req);
|
|
171
|
+
if (!user_id) {
|
|
172
|
+
return res.json({ code: NO_SESSION });
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const user = await user_entity.find_one({ _id: user_id }, {});
|
|
176
|
+
return res.json({ code: SUCCESS, data: user });
|
|
177
|
+
});
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Pattern 4: Ownership-Based Access
|
|
181
|
+
|
|
182
|
+
```javascript
|
|
183
|
+
// Meta definition with ownership
|
|
184
|
+
const meta = {
|
|
185
|
+
collection: "document",
|
|
186
|
+
user_field: "owner_id", // Links document to user
|
|
187
|
+
fields: [
|
|
188
|
+
{ name: "title", type: "string" },
|
|
189
|
+
{ name: "owner_id", ref: "user" }
|
|
190
|
+
]
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// Route using ownership check
|
|
194
|
+
const { NO_RIGHTS } = require("hola-server/http/code");
|
|
195
|
+
|
|
196
|
+
router.delete("/:id", async (req, res) => {
|
|
197
|
+
const query = { _id: req.params.id };
|
|
198
|
+
const entity = new Entity(meta);
|
|
199
|
+
|
|
200
|
+
if (!await is_owner(req, meta, entity, query)) {
|
|
201
|
+
return res.json({ code: NO_RIGHTS });
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const result = await entity.delete_entity([req.params.id]);
|
|
205
|
+
return res.json(result);
|
|
206
|
+
});
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Pattern 5: Group-Based Access
|
|
210
|
+
|
|
211
|
+
```javascript
|
|
212
|
+
const { NO_RIGHTS, SUCCESS } = require("hola-server/http/code");
|
|
213
|
+
|
|
214
|
+
router.post("/admin/action", async (req, res) => {
|
|
215
|
+
const groups = get_session_user_groups(req);
|
|
216
|
+
|
|
217
|
+
if (!groups || !groups.includes("admin")) {
|
|
218
|
+
return res.json({ code: NO_RIGHTS });
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Perform admin action
|
|
222
|
+
await perform_admin_action(req.body);
|
|
223
|
+
return res.json({ code: SUCCESS });
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Pattern 6: Auto-Set Owner on Create
|
|
228
|
+
|
|
229
|
+
```javascript
|
|
230
|
+
const { NO_SESSION } = require("hola-server/http/code");
|
|
231
|
+
|
|
232
|
+
router.post("/document", async (req, res) => {
|
|
233
|
+
const user_id = get_session_user_id(req);
|
|
234
|
+
if (!user_id) {
|
|
235
|
+
return res.json({ code: NO_SESSION });
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Automatically set owner
|
|
239
|
+
req.body.owner_id = user_id;
|
|
240
|
+
|
|
241
|
+
const result = await entity.create_entity(req.body, "*");
|
|
242
|
+
return res.json(result);
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Session Storage
|
|
247
|
+
|
|
248
|
+
Sessions are stored in MongoDB via `connect-mongo`:
|
|
249
|
+
- Collection: `sessions` (created automatically)
|
|
250
|
+
- Expires: Based on `cookie_max_age` setting
|
|
251
|
+
- Cleanup: Automatic (expired sessions removed by MongoDB TTL)
|
|
252
|
+
|
|
253
|
+
## Best Practices
|
|
254
|
+
|
|
255
|
+
1. **Always validate session**: Check `get_session_user_id()` in protected routes.
|
|
256
|
+
|
|
257
|
+
2. **Use secure secrets**: Never commit session secret to version control.
|
|
258
|
+
```javascript
|
|
259
|
+
// Good: from environment
|
|
260
|
+
"secret": process.env.SESSION_SECRET
|
|
261
|
+
|
|
262
|
+
// Bad: hardcoded
|
|
263
|
+
"secret": "my-secret-123"
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
3. **Set appropriate cookie age**: Balance security vs. user convenience.
|
|
267
|
+
```javascript
|
|
268
|
+
"cookie_max_age": 3600000 // 1 hour for high-security
|
|
269
|
+
"cookie_max_age": 604800000 // 7 days for convenience
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
4. **Use HTTPS in production**: Session cookies should use `secure` flag.
|
|
273
|
+
|
|
274
|
+
5. **Implement ownership where applicable**: Use `user_field` in meta for user-owned data.
|
|
275
|
+
|
|
276
|
+
## Security Considerations
|
|
277
|
+
|
|
278
|
+
- **Session fixation**: Express-session regenerates session ID on login
|
|
279
|
+
- **XSS protection**: Don't expose session data to client-side JavaScript
|
|
280
|
+
- **CSRF**: Consider adding CSRF tokens for state-changing operations
|
|
281
|
+
- **Session hijacking**: Use HTTPS and secure cookies in production
|