@adonisjs/session 6.4.0 → 7.0.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 +25 -42
- package/build/configure.d.ts +5 -0
- package/build/configure.js +18 -0
- package/build/index.d.ts +12 -0
- package/build/index.js +12 -0
- package/build/providers/session_provider.d.ts +13 -0
- package/build/providers/session_provider.js +43 -0
- package/build/src/bindings/api_client.d.ts +2 -0
- package/build/src/{Bindings/Tests.js → bindings/api_client.js} +8 -13
- package/build/src/bindings/http_context.d.ts +5 -0
- package/build/src/bindings/http_context.js +17 -0
- package/build/{adonis-typings/tests.d.ts → src/bindings/types.d.ts} +26 -5
- package/build/{adonis-typings/session.js → src/bindings/types.js} +2 -1
- package/build/src/{Client/index.d.ts → client.d.ts} +7 -15
- package/build/src/client.js +100 -0
- package/build/src/define_config.d.ts +5 -0
- package/build/src/define_config.js +13 -0
- package/build/src/{Drivers/Cookie.d.ts → drivers/cookie.d.ts} +4 -6
- package/build/src/{Drivers/Cookie.js → drivers/cookie.js} +10 -12
- package/build/src/{Drivers/File.d.ts → drivers/file.d.ts} +3 -8
- package/build/src/{Drivers/File.js → drivers/file.js} +20 -23
- package/build/src/{Drivers/Memory.d.ts → drivers/memory.d.ts} +2 -3
- package/build/src/{Drivers/Memory.js → drivers/memory.js} +3 -7
- package/build/src/{Drivers/Redis.d.ts → drivers/redis.d.ts} +5 -15
- package/build/src/drivers/redis.js +74 -0
- package/build/src/{Session/index.d.ts → session.d.ts} +6 -67
- package/build/src/session.js +371 -0
- package/build/src/session_manager.d.ts +38 -0
- package/build/src/session_manager.js +149 -0
- package/build/src/session_middleware.d.ts +5 -0
- package/build/src/session_middleware.js +20 -0
- package/build/src/{Store/index.d.ts → store.d.ts} +3 -7
- package/build/src/{Store/index.js → store.js} +18 -18
- package/build/src/types.d.ts +61 -0
- package/build/src/types.js +1 -0
- package/build/{templates/session.txt → stubs/config.stub} +12 -15
- package/build/stubs/main.d.ts +1 -0
- package/build/{adonis-typings/tests.js → stubs/main.js} +2 -3
- package/package.json +96 -134
- package/build/adonis-typings/container.d.ts +0 -14
- package/build/adonis-typings/container.js +0 -8
- package/build/adonis-typings/context.d.ts +0 -14
- package/build/adonis-typings/context.js +0 -8
- package/build/adonis-typings/index.d.ts +0 -4
- package/build/adonis-typings/index.js +0 -12
- package/build/adonis-typings/session.d.ts +0 -265
- package/build/config.d.ts +0 -13
- package/build/config.js +0 -18
- package/build/instructions.md +0 -10
- package/build/providers/SessionProvider.d.ts +0 -31
- package/build/providers/SessionProvider.js +0 -56
- package/build/src/Bindings/Server.d.ts +0 -10
- package/build/src/Bindings/Server.js +0 -42
- package/build/src/Bindings/Tests.d.ts +0 -7
- package/build/src/Client/index.js +0 -93
- package/build/src/Drivers/Redis.js +0 -73
- package/build/src/Session/index.js +0 -352
- package/build/src/SessionManager/index.d.ts +0 -78
- package/build/src/SessionManager/index.js +0 -148
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/session
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { Exception } from '@poppinss/utils';
|
|
10
|
+
import lodash from '@poppinss/utils/lodash';
|
|
11
|
+
import { cuid } from '@adonisjs/core/helpers';
|
|
12
|
+
import { Store } from './store.js';
|
|
13
|
+
/**
|
|
14
|
+
* Session class exposes the API to read/write values to the session for
|
|
15
|
+
* a given request.
|
|
16
|
+
*/
|
|
17
|
+
export class Session {
|
|
18
|
+
/**
|
|
19
|
+
* Session id for the current request. It will be different
|
|
20
|
+
* from the "this.sessionId" when regenerate is called.
|
|
21
|
+
*/
|
|
22
|
+
#currentSessionId;
|
|
23
|
+
/**
|
|
24
|
+
* A instance of store with values read from the driver. The store
|
|
25
|
+
* in initiated inside the [[initiate]] method
|
|
26
|
+
*/
|
|
27
|
+
#store;
|
|
28
|
+
/**
|
|
29
|
+
* Whether or not to re-generate the session id before committing
|
|
30
|
+
* session values.
|
|
31
|
+
*/
|
|
32
|
+
#regeneratedSessionId = false;
|
|
33
|
+
/**
|
|
34
|
+
* Session key for setting flash messages
|
|
35
|
+
*/
|
|
36
|
+
#flashMessagesKey = '__flash__';
|
|
37
|
+
/**
|
|
38
|
+
* The HTTP context for the current request.
|
|
39
|
+
*/
|
|
40
|
+
#ctx;
|
|
41
|
+
/**
|
|
42
|
+
* Configuration for the session
|
|
43
|
+
*/
|
|
44
|
+
#config;
|
|
45
|
+
/**
|
|
46
|
+
* The session driver instance used to read and write session data.
|
|
47
|
+
*/
|
|
48
|
+
#driver;
|
|
49
|
+
/**
|
|
50
|
+
* Set to true inside the `initiate` method
|
|
51
|
+
*/
|
|
52
|
+
initiated = false;
|
|
53
|
+
/**
|
|
54
|
+
* A boolean to know if it's a fresh session or not. Fresh
|
|
55
|
+
* sessions are those, whose session id is not present
|
|
56
|
+
* in cookie
|
|
57
|
+
*/
|
|
58
|
+
fresh = false;
|
|
59
|
+
/**
|
|
60
|
+
* A boolean to know if store is initiated in readonly mode
|
|
61
|
+
* or not. This is done during Websocket requests
|
|
62
|
+
*/
|
|
63
|
+
readonly = false;
|
|
64
|
+
/**
|
|
65
|
+
* Session id for the given request. A new session id is only
|
|
66
|
+
* generated when the cookie for the session id is missing
|
|
67
|
+
*/
|
|
68
|
+
sessionId;
|
|
69
|
+
/**
|
|
70
|
+
* A copy of previously set flash messages
|
|
71
|
+
*/
|
|
72
|
+
flashMessages = new Store({});
|
|
73
|
+
/**
|
|
74
|
+
* A copy of flash messages. The `input` messages
|
|
75
|
+
* are overwritten when any of the input related
|
|
76
|
+
* methods are used.
|
|
77
|
+
*
|
|
78
|
+
* The `others` object is expanded with each call.
|
|
79
|
+
*/
|
|
80
|
+
responseFlashMessages = new Store({});
|
|
81
|
+
constructor(ctx, config, driver) {
|
|
82
|
+
this.#ctx = ctx;
|
|
83
|
+
this.#config = config;
|
|
84
|
+
this.#driver = driver;
|
|
85
|
+
this.sessionId = this.#getSessionId();
|
|
86
|
+
this.#currentSessionId = this.sessionId;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Returns a merged copy of flash messages or null
|
|
90
|
+
* when nothing is set
|
|
91
|
+
*/
|
|
92
|
+
#setFlashMessages() {
|
|
93
|
+
if (this.responseFlashMessages.isEmpty) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const { input, ...others } = this.responseFlashMessages.all();
|
|
97
|
+
this.put(this.#flashMessagesKey, { ...input, ...others });
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Returns the existing session id or creates one.
|
|
101
|
+
*/
|
|
102
|
+
#getSessionId() {
|
|
103
|
+
const sessionId = this.#ctx.request.cookie(this.#config.cookieName);
|
|
104
|
+
if (sessionId) {
|
|
105
|
+
return sessionId;
|
|
106
|
+
}
|
|
107
|
+
this.fresh = true;
|
|
108
|
+
return cuid();
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Ensures the session store is initialized
|
|
112
|
+
*/
|
|
113
|
+
#ensureIsReady() {
|
|
114
|
+
if (!this.initiated) {
|
|
115
|
+
throw new Exception('Session store is not initiated yet. Make sure you are using the session hook', { code: 'E_RUNTIME_EXCEPTION', status: 500 });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Raises exception when session store is in readonly mode
|
|
120
|
+
*/
|
|
121
|
+
#ensureIsMutable() {
|
|
122
|
+
if (this.readonly) {
|
|
123
|
+
throw new Exception('Session store is in readonly mode and cannot be mutated', {
|
|
124
|
+
status: 500,
|
|
125
|
+
code: 'E_RUNTIME_EXCEPTION',
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Touches the session cookie
|
|
131
|
+
*/
|
|
132
|
+
#touchSessionCookie() {
|
|
133
|
+
this.#ctx.logger.trace('touching session cookie');
|
|
134
|
+
this.#ctx.response.cookie(this.#config.cookieName, this.sessionId, this.#config.cookie);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Commits the session value to the store
|
|
138
|
+
*/
|
|
139
|
+
async #commitValuesToStore() {
|
|
140
|
+
this.#ctx.logger.trace('persist session store with driver');
|
|
141
|
+
await this.#driver.write(this.sessionId, this.#store.toJSON());
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Touches the driver to make sure the session values doesn't expire
|
|
145
|
+
*/
|
|
146
|
+
async #touchDriver() {
|
|
147
|
+
this.#ctx.logger.trace('touch driver for liveliness');
|
|
148
|
+
await this.#driver.touch(this.sessionId);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Reading flash messages from the last HTTP request and
|
|
152
|
+
* updating the flash messages bag
|
|
153
|
+
*/
|
|
154
|
+
#readLastRequestFlashMessage() {
|
|
155
|
+
if (this.readonly) {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
this.flashMessages.update(this.pull(this.#flashMessagesKey, null));
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Share flash messages & read only session's functions with views
|
|
162
|
+
* (only when view property exists)
|
|
163
|
+
*/
|
|
164
|
+
#shareLocalsWithView() {
|
|
165
|
+
if (!this.#ctx['view'] || typeof this.#ctx['view'].share !== 'function') {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
this.#ctx['view'].share({
|
|
169
|
+
flashMessages: this.flashMessages,
|
|
170
|
+
session: {
|
|
171
|
+
get: this.get.bind(this),
|
|
172
|
+
has: this.has.bind(this),
|
|
173
|
+
all: this.all.bind(this),
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Initiating the session by reading it's value from the
|
|
179
|
+
* driver and feeding it to a store.
|
|
180
|
+
*
|
|
181
|
+
* Multiple calls to `initiate` results in a noop.
|
|
182
|
+
*/
|
|
183
|
+
async initiate(readonly) {
|
|
184
|
+
if (this.initiated) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
this.readonly = readonly;
|
|
188
|
+
const contents = await this.#driver.read(this.sessionId);
|
|
189
|
+
this.#store = new Store(contents);
|
|
190
|
+
this.initiated = true;
|
|
191
|
+
this.#readLastRequestFlashMessage();
|
|
192
|
+
this.#shareLocalsWithView();
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Re-generates the session id. This can is used to avoid
|
|
196
|
+
* session fixation attacks.
|
|
197
|
+
*/
|
|
198
|
+
regenerate() {
|
|
199
|
+
this.#ctx.logger.trace('explicitly re-generating session id');
|
|
200
|
+
this.sessionId = cuid();
|
|
201
|
+
this.#regeneratedSessionId = true;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Set/update session value
|
|
205
|
+
*/
|
|
206
|
+
put(key, value) {
|
|
207
|
+
this.#ensureIsReady();
|
|
208
|
+
this.#ensureIsMutable();
|
|
209
|
+
this.#store.set(key, value);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Find if the value exists in the session
|
|
213
|
+
*/
|
|
214
|
+
has(key) {
|
|
215
|
+
this.#ensureIsReady();
|
|
216
|
+
return this.#store.has(key);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Get value from the session. The default value is returned
|
|
220
|
+
* when actual value is `undefined`
|
|
221
|
+
*/
|
|
222
|
+
get(key, defaultValue) {
|
|
223
|
+
this.#ensureIsReady();
|
|
224
|
+
return this.#store.get(key, defaultValue);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Returns everything from the session
|
|
228
|
+
*/
|
|
229
|
+
all() {
|
|
230
|
+
this.#ensureIsReady();
|
|
231
|
+
return this.#store.all();
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Remove value for a given key from the session
|
|
235
|
+
*/
|
|
236
|
+
forget(key) {
|
|
237
|
+
this.#ensureIsReady();
|
|
238
|
+
this.#ensureIsMutable();
|
|
239
|
+
this.#store.unset(key);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* The method is equivalent to calling `session.get` followed
|
|
243
|
+
* by `session.forget`
|
|
244
|
+
*/
|
|
245
|
+
pull(key, defaultValue) {
|
|
246
|
+
this.#ensureIsReady();
|
|
247
|
+
this.#ensureIsMutable();
|
|
248
|
+
return this.#store.pull(key, defaultValue);
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Increment value for a number inside the session store. The
|
|
252
|
+
* method raises an error when underlying value is not
|
|
253
|
+
* a number
|
|
254
|
+
*/
|
|
255
|
+
increment(key, steps = 1) {
|
|
256
|
+
this.#ensureIsReady();
|
|
257
|
+
this.#ensureIsMutable();
|
|
258
|
+
this.#store.increment(key, steps);
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Decrement value for a number inside the session store. The
|
|
262
|
+
* method raises an error when underlying value is not
|
|
263
|
+
* a number
|
|
264
|
+
*/
|
|
265
|
+
decrement(key, steps = 1) {
|
|
266
|
+
this.#ensureIsReady();
|
|
267
|
+
this.#ensureIsMutable();
|
|
268
|
+
this.#store.decrement(key, steps);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Remove everything from the session
|
|
272
|
+
*/
|
|
273
|
+
clear() {
|
|
274
|
+
this.#ensureIsReady();
|
|
275
|
+
this.#ensureIsMutable();
|
|
276
|
+
this.#store.clear();
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Add a new flash message
|
|
280
|
+
*/
|
|
281
|
+
flash(key, value) {
|
|
282
|
+
this.#ensureIsReady();
|
|
283
|
+
this.#ensureIsMutable();
|
|
284
|
+
/**
|
|
285
|
+
* Update value
|
|
286
|
+
*/
|
|
287
|
+
if (typeof key === 'string') {
|
|
288
|
+
if (value) {
|
|
289
|
+
this.responseFlashMessages.set(key, value);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
this.responseFlashMessages.merge(key);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Flash all form values
|
|
298
|
+
*/
|
|
299
|
+
flashAll() {
|
|
300
|
+
this.#ensureIsReady();
|
|
301
|
+
this.#ensureIsMutable();
|
|
302
|
+
this.responseFlashMessages.set('input', this.#ctx.request.original());
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Flash all form values except mentioned keys
|
|
306
|
+
*/
|
|
307
|
+
flashExcept(keys) {
|
|
308
|
+
this.#ensureIsReady();
|
|
309
|
+
this.#ensureIsMutable();
|
|
310
|
+
this.responseFlashMessages.set('input', lodash.omit(this.#ctx.request.original(), keys));
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Flash only defined keys from the form values
|
|
314
|
+
*/
|
|
315
|
+
flashOnly(keys) {
|
|
316
|
+
this.#ensureIsReady();
|
|
317
|
+
this.#ensureIsMutable();
|
|
318
|
+
this.responseFlashMessages.set('input', lodash.pick(this.#ctx.request.original(), keys));
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Reflash existing flash messages
|
|
322
|
+
*/
|
|
323
|
+
reflash() {
|
|
324
|
+
this.flash(this.flashMessages.all());
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Reflash selected keys from the existing flash messages
|
|
328
|
+
*/
|
|
329
|
+
reflashOnly(keys) {
|
|
330
|
+
this.flash(lodash.pick(this.flashMessages.all(), keys));
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Omit selected keys from the existing flash messages
|
|
334
|
+
* and flash the rest of values
|
|
335
|
+
*/
|
|
336
|
+
reflashExcept(keys) {
|
|
337
|
+
this.flash(lodash.omit(this.flashMessages.all(), keys));
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Writes value to the underlying session driver.
|
|
341
|
+
*/
|
|
342
|
+
async commit() {
|
|
343
|
+
if (!this.initiated) {
|
|
344
|
+
this.#touchSessionCookie();
|
|
345
|
+
await this.#touchDriver();
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Cleanup old session and re-generate new session
|
|
350
|
+
*/
|
|
351
|
+
if (this.#regeneratedSessionId) {
|
|
352
|
+
await this.#driver.destroy(this.#currentSessionId);
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Touch the session cookie to keep it alive.
|
|
356
|
+
*/
|
|
357
|
+
this.#touchSessionCookie();
|
|
358
|
+
this.#setFlashMessages();
|
|
359
|
+
/**
|
|
360
|
+
* Commit values to the store if not empty.
|
|
361
|
+
* Otherwise delete the session store to cleanup
|
|
362
|
+
* the storage space.
|
|
363
|
+
*/
|
|
364
|
+
if (!this.#store.isEmpty) {
|
|
365
|
+
await this.#commitValuesToStore();
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
await this.#driver.destroy(this.sessionId);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adonisjs/session
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { Session } from './session.js';
|
|
10
|
+
import { HttpContext } from '@adonisjs/core/http';
|
|
11
|
+
import { ExtendCallback, SessionConfig } from './types.js';
|
|
12
|
+
import { RedisManagerContract } from '@adonisjs/redis/types';
|
|
13
|
+
import { Encryption } from '@adonisjs/core/encryption';
|
|
14
|
+
import { SessionClient } from './client.js';
|
|
15
|
+
/**
|
|
16
|
+
* Session manager exposes the API to create session instance for a given
|
|
17
|
+
* request and also add new drivers.
|
|
18
|
+
*/
|
|
19
|
+
export declare class SessionManager {
|
|
20
|
+
#private;
|
|
21
|
+
constructor(config: SessionConfig, encryption: Encryption, redis?: RedisManagerContract<any>);
|
|
22
|
+
/**
|
|
23
|
+
* Find if the sessions are enabled
|
|
24
|
+
*/
|
|
25
|
+
isEnabled(): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Creates an instance of the session client
|
|
28
|
+
*/
|
|
29
|
+
client(): SessionClient;
|
|
30
|
+
/**
|
|
31
|
+
* Creates a new session instance for a given HTTP request
|
|
32
|
+
*/
|
|
33
|
+
create(ctx: HttpContext): Session;
|
|
34
|
+
/**
|
|
35
|
+
* Extend the drivers list by adding a new one.
|
|
36
|
+
*/
|
|
37
|
+
extend(driver: string, callback: ExtendCallback): void;
|
|
38
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adonisjs/session
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import string from '@poppinss/utils/string';
|
|
10
|
+
import { Exception } from '@poppinss/utils';
|
|
11
|
+
import { Session } from './session.js';
|
|
12
|
+
import { CookieClient } from '@adonisjs/core/http';
|
|
13
|
+
import { CookieDriver } from './drivers/cookie.js';
|
|
14
|
+
import { MemoryDriver } from './drivers/memory.js';
|
|
15
|
+
import { FileDriver } from './drivers/file.js';
|
|
16
|
+
import { RedisDriver } from './drivers/redis.js';
|
|
17
|
+
import { SessionClient } from './client.js';
|
|
18
|
+
/**
|
|
19
|
+
* Session manager exposes the API to create session instance for a given
|
|
20
|
+
* request and also add new drivers.
|
|
21
|
+
*/
|
|
22
|
+
export class SessionManager {
|
|
23
|
+
/**
|
|
24
|
+
* A private map of drivers added from outside in.
|
|
25
|
+
*/
|
|
26
|
+
#extendedDrivers = new Map();
|
|
27
|
+
/**
|
|
28
|
+
* Reference to session config
|
|
29
|
+
*/
|
|
30
|
+
#config;
|
|
31
|
+
/**
|
|
32
|
+
* Reference to the encryption instance
|
|
33
|
+
*/
|
|
34
|
+
#encryption;
|
|
35
|
+
/**
|
|
36
|
+
* Reference to the redis manager
|
|
37
|
+
*/
|
|
38
|
+
#redis;
|
|
39
|
+
constructor(config, encryption, redis) {
|
|
40
|
+
this.#encryption = encryption;
|
|
41
|
+
this.#redis = redis;
|
|
42
|
+
this.#processConfig(config);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Processes the config and decides the `expires` option for the cookie
|
|
46
|
+
*/
|
|
47
|
+
#processConfig(config) {
|
|
48
|
+
/**
|
|
49
|
+
* Explicitly overwriting `cookie.expires` and `cookie.maxAge` from
|
|
50
|
+
* the user defined config
|
|
51
|
+
*/
|
|
52
|
+
const processedConfig = Object.assign({ enabled: true }, config, {
|
|
53
|
+
cookie: {
|
|
54
|
+
...config.cookie,
|
|
55
|
+
expires: undefined,
|
|
56
|
+
maxAge: undefined,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
/**
|
|
60
|
+
* Set the max age when `clearWithBrowser = false`. Otherwise cookie
|
|
61
|
+
* is a session cookie
|
|
62
|
+
*/
|
|
63
|
+
if (!processedConfig.clearWithBrowser) {
|
|
64
|
+
const age = typeof processedConfig.age === 'string'
|
|
65
|
+
? Math.round(string.milliseconds.parse(processedConfig.age) / 1000)
|
|
66
|
+
: processedConfig.age;
|
|
67
|
+
processedConfig.cookie.maxAge = age;
|
|
68
|
+
}
|
|
69
|
+
this.#config = processedConfig;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Returns an instance of cookie driver
|
|
73
|
+
*/
|
|
74
|
+
#createCookieDriver(ctx) {
|
|
75
|
+
return new CookieDriver(this.#config, ctx);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Returns an instance of the memory driver
|
|
79
|
+
*/
|
|
80
|
+
#createMemoryDriver() {
|
|
81
|
+
return new MemoryDriver();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Returns an instance of file driver
|
|
85
|
+
*/
|
|
86
|
+
#createFileDriver() {
|
|
87
|
+
return new FileDriver(this.#config);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Returns an instance of redis driver
|
|
91
|
+
*/
|
|
92
|
+
#createRedisDriver() {
|
|
93
|
+
if (!this.#redis) {
|
|
94
|
+
throw new Error('Install "@adonisjs/redis" in order to use the redis driver for storing sessions');
|
|
95
|
+
}
|
|
96
|
+
return new RedisDriver(this.#config, this.#redis);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Creates an instance of extended driver
|
|
100
|
+
*/
|
|
101
|
+
#createExtendedDriver(ctx) {
|
|
102
|
+
if (!this.#extendedDrivers.has(this.#config.driver)) {
|
|
103
|
+
throw new Exception(`"${this.#config.driver}" is not a valid session driver`, {
|
|
104
|
+
code: 'E_INVALID_SESSION_DRIVER',
|
|
105
|
+
status: 500,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return this.#extendedDrivers.get(this.#config.driver)(this, this.#config, ctx);
|
|
109
|
+
}
|
|
110
|
+
#createDriver(ctx) {
|
|
111
|
+
switch (this.#config.driver) {
|
|
112
|
+
case 'cookie':
|
|
113
|
+
return this.#createCookieDriver(ctx);
|
|
114
|
+
case 'file':
|
|
115
|
+
return this.#createFileDriver();
|
|
116
|
+
case 'redis':
|
|
117
|
+
return this.#createRedisDriver();
|
|
118
|
+
case 'memory':
|
|
119
|
+
return this.#createMemoryDriver();
|
|
120
|
+
default:
|
|
121
|
+
return this.#createExtendedDriver(ctx);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Find if the sessions are enabled
|
|
126
|
+
*/
|
|
127
|
+
isEnabled() {
|
|
128
|
+
return this.#config.enabled;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Creates an instance of the session client
|
|
132
|
+
*/
|
|
133
|
+
client() {
|
|
134
|
+
const cookieClient = new CookieClient(this.#encryption);
|
|
135
|
+
return new SessionClient(this.#config, this.#createMemoryDriver(), cookieClient, {});
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Creates a new session instance for a given HTTP request
|
|
139
|
+
*/
|
|
140
|
+
create(ctx) {
|
|
141
|
+
return new Session(ctx, this.#config, this.#createDriver(ctx));
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Extend the drivers list by adding a new one.
|
|
145
|
+
*/
|
|
146
|
+
extend(driver, callback) {
|
|
147
|
+
this.#extendedDrivers.set(driver, callback);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export default class SessionMiddleware {
|
|
2
|
+
async handle(ctx, next) {
|
|
3
|
+
const sessionManager = (await ctx.containerResolver.make('session'));
|
|
4
|
+
if (!sessionManager.isEnabled()) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Initiate session store
|
|
9
|
+
*/
|
|
10
|
+
await ctx.session.initiate(false);
|
|
11
|
+
/**
|
|
12
|
+
* Call next middlewares or route handler
|
|
13
|
+
*/
|
|
14
|
+
await next();
|
|
15
|
+
/**
|
|
16
|
+
* Commit store mutations
|
|
17
|
+
*/
|
|
18
|
+
await ctx.session.commit();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
import { AllowedSessionValues, StoreContract } from '@ioc:Adonis/Addons/Session';
|
|
1
|
+
import type { AllowedSessionValues } from './types.js';
|
|
3
2
|
/**
|
|
4
3
|
* Session store to mutate and access values from the session object
|
|
5
4
|
*/
|
|
6
|
-
export declare class Store
|
|
7
|
-
|
|
8
|
-
* Underlying store values
|
|
9
|
-
*/
|
|
10
|
-
private values;
|
|
5
|
+
export declare class Store {
|
|
6
|
+
#private;
|
|
11
7
|
constructor(values: {
|
|
12
8
|
[key: string]: any;
|
|
13
9
|
} | null);
|
|
@@ -1,46 +1,47 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/*
|
|
3
2
|
* @adonisjs/redis
|
|
4
3
|
*
|
|
5
|
-
* (c)
|
|
4
|
+
* (c) AdonisJS
|
|
6
5
|
*
|
|
7
6
|
* For the full copyright and license information, please view the LICENSE
|
|
8
7
|
* file that was distributed with this source code.
|
|
9
8
|
*/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/// <reference path="../../adonis-typings/index.ts" />
|
|
13
|
-
const utils_1 = require("@poppinss/utils");
|
|
9
|
+
import { Exception } from '@poppinss/utils';
|
|
10
|
+
import lodash from '@poppinss/utils/lodash';
|
|
14
11
|
/**
|
|
15
12
|
* Session store to mutate and access values from the session object
|
|
16
13
|
*/
|
|
17
|
-
class Store {
|
|
14
|
+
export class Store {
|
|
15
|
+
/**
|
|
16
|
+
* Underlying store values
|
|
17
|
+
*/
|
|
18
|
+
#values;
|
|
18
19
|
constructor(values) {
|
|
19
|
-
this
|
|
20
|
+
this.#values = values || {};
|
|
20
21
|
}
|
|
21
22
|
/**
|
|
22
23
|
* Find if store is empty or not
|
|
23
24
|
*/
|
|
24
25
|
get isEmpty() {
|
|
25
|
-
return !this
|
|
26
|
+
return !this.#values || Object.keys(this.#values).length === 0;
|
|
26
27
|
}
|
|
27
28
|
/**
|
|
28
29
|
* Set key/value pair
|
|
29
30
|
*/
|
|
30
31
|
set(key, value) {
|
|
31
|
-
|
|
32
|
+
lodash.set(this.#values, key, value);
|
|
32
33
|
}
|
|
33
34
|
/**
|
|
34
35
|
* Get value for a given key
|
|
35
36
|
*/
|
|
36
37
|
get(key, defaultValue) {
|
|
37
|
-
return
|
|
38
|
+
return lodash.get(this.#values, key, defaultValue);
|
|
38
39
|
}
|
|
39
40
|
/**
|
|
40
41
|
* Remove key
|
|
41
42
|
*/
|
|
42
43
|
unset(key) {
|
|
43
|
-
|
|
44
|
+
lodash.unset(this.#values, key);
|
|
44
45
|
}
|
|
45
46
|
/**
|
|
46
47
|
* Reset store by clearing it's values.
|
|
@@ -65,7 +66,7 @@ class Store {
|
|
|
65
66
|
increment(key, steps = 1) {
|
|
66
67
|
const value = this.get(key, 0);
|
|
67
68
|
if (typeof value !== 'number') {
|
|
68
|
-
throw new
|
|
69
|
+
throw new Exception(`Cannot increment "${key}", since original value is not a number`);
|
|
69
70
|
}
|
|
70
71
|
this.set(key, value + steps);
|
|
71
72
|
}
|
|
@@ -76,7 +77,7 @@ class Store {
|
|
|
76
77
|
decrement(key, steps = 1) {
|
|
77
78
|
const value = this.get(key, 0);
|
|
78
79
|
if (typeof value !== 'number') {
|
|
79
|
-
throw new
|
|
80
|
+
throw new Exception(`Cannot increment "${key}", since original value is not a number`);
|
|
80
81
|
}
|
|
81
82
|
this.set(key, value - steps);
|
|
82
83
|
}
|
|
@@ -84,13 +85,13 @@ class Store {
|
|
|
84
85
|
* Overwrite the underlying values object
|
|
85
86
|
*/
|
|
86
87
|
update(values) {
|
|
87
|
-
this
|
|
88
|
+
this.#values = values;
|
|
88
89
|
}
|
|
89
90
|
/**
|
|
90
91
|
* Update to merge values
|
|
91
92
|
*/
|
|
92
93
|
merge(values) {
|
|
93
|
-
|
|
94
|
+
lodash.merge(this.#values, values);
|
|
94
95
|
}
|
|
95
96
|
/**
|
|
96
97
|
* A boolean to know if value exists. Extra guards to check
|
|
@@ -107,7 +108,7 @@ class Store {
|
|
|
107
108
|
* Get all values
|
|
108
109
|
*/
|
|
109
110
|
all() {
|
|
110
|
-
return this
|
|
111
|
+
return this.#values;
|
|
111
112
|
}
|
|
112
113
|
/**
|
|
113
114
|
* Returns object representation of values
|
|
@@ -128,4 +129,3 @@ class Store {
|
|
|
128
129
|
return JSON.stringify(this.all());
|
|
129
130
|
}
|
|
130
131
|
}
|
|
131
|
-
exports.Store = Store;
|