@proteinjs/user-server 1.10.1 → 1.10.3
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/CHANGELOG.md +22 -0
- package/dist/src/authentication/establishSession.d.ts +9 -2
- package/dist/src/authentication/establishSession.d.ts.map +1 -1
- package/dist/src/authentication/establishSession.js +23 -5
- package/dist/src/authentication/establishSession.js.map +1 -1
- package/dist/src/routes/avatar.d.ts +4 -1
- package/dist/src/routes/avatar.d.ts.map +1 -1
- package/dist/src/routes/avatar.js +5 -2
- package/dist/src/routes/avatar.js.map +1 -1
- package/dist/test/DevLoginStaleCookieFirstHit.test.d.ts +2 -0
- package/dist/test/DevLoginStaleCookieFirstHit.test.d.ts.map +1 -0
- package/dist/test/DevLoginStaleCookieFirstHit.test.js +401 -0
- package/dist/test/DevLoginStaleCookieFirstHit.test.js.map +1 -0
- package/dist/test/EstablishSessionRuntimeContract.test.d.ts +2 -0
- package/dist/test/EstablishSessionRuntimeContract.test.d.ts.map +1 -0
- package/dist/test/EstablishSessionRuntimeContract.test.js +114 -0
- package/dist/test/EstablishSessionRuntimeContract.test.js.map +1 -0
- package/dist/test/MachineAccounts.integration.test.js.map +1 -1
- package/dist/test/UpdateUserInfoAvatar.test.js +5 -3
- package/dist/test/UpdateUserInfoAvatar.test.js.map +1 -1
- package/package.json +2 -2
- package/src/authentication/establishSession.ts +20 -2
- package/src/routes/avatar.ts +5 -2
- package/test/DevLoginStaleCookieFirstHit.test.ts +304 -0
- package/test/EstablishSessionRuntimeContract.test.ts +54 -0
- package/test/UpdateUserInfoAvatar.test.ts +3 -2
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { establishSession } from '../src/authentication/establishSession';
|
|
2
|
+
import { createPassportRequest } from './passportSessionHarness';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* establishSession's post-condition: `request.login` must have REPLACED `request.session`
|
|
6
|
+
* (express-session's regenerate always assigns a fresh Session object — the fresh sid the
|
|
7
|
+
* commit-before-response save then writes under). Passport 0.6 honors that on every login;
|
|
8
|
+
* a pre-0.6 passport runtime (@proteinjs/server < 3.5.1) resolves the login WITHOUT
|
|
9
|
+
* regenerating or saving — silently reopening the session-fixation hole (CVE-2022-25896) AND
|
|
10
|
+
* the first-hit race (the post-login navigation beating the deferred session write — the
|
|
11
|
+
* /dev/login lands-on-login-form smoke finding, DEV_SMOKE_OVERNIGHT 2026-08-26 #7).
|
|
12
|
+
*
|
|
13
|
+
* The guard turns that silent degradation into a loud, seam-naming failure at the one owner of
|
|
14
|
+
* session establishment. DevLoginStaleCookieFirstHit.test.ts proves the honored contract
|
|
15
|
+
* through the real middleware stack; this suite pins the refusal when the runtime cannot honor
|
|
16
|
+
* it.
|
|
17
|
+
*/
|
|
18
|
+
describe('establishSession runtime contract', () => {
|
|
19
|
+
it('rejects, naming the seam, when login resolves without replacing the session (pre-0.6 passport shape)', async () => {
|
|
20
|
+
const session: Record<string, unknown> = {};
|
|
21
|
+
const request = {
|
|
22
|
+
session,
|
|
23
|
+
login(user: string, cb: (error?: unknown) => void) {
|
|
24
|
+
// passport 0.4's SessionManager.logIn: bind onto the SAME session object, no
|
|
25
|
+
// regenerate, no save — the stale-runtime shape the guard must refuse.
|
|
26
|
+
session.passport = { user };
|
|
27
|
+
cb();
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
await expect(establishSession(request, 'dev@test.local')).rejects.toThrow(/@proteinjs\/server/);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('resolves through the real passport 0.6 machinery, user bound on the post-regeneration session', async () => {
|
|
35
|
+
const { request, events } = await createPassportRequest();
|
|
36
|
+
|
|
37
|
+
await establishSession(request, 'dev@test.local');
|
|
38
|
+
|
|
39
|
+
expect(request.session.passport.user).toBe('dev@test.local');
|
|
40
|
+
expect(events).toEqual(['regenerate', 'login', 'save']);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('still surfaces a login failure as a rejection (never as the contract error)', async () => {
|
|
44
|
+
const loginError = new Error('serialize blew up');
|
|
45
|
+
const request = {
|
|
46
|
+
session: {},
|
|
47
|
+
login(_user: string, cb: (error?: unknown) => void) {
|
|
48
|
+
cb(loginError);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
await expect(establishSession(request, 'dev@test.local')).rejects.toThrow('serialize blew up');
|
|
53
|
+
});
|
|
54
|
+
});
|
|
@@ -79,9 +79,10 @@ describe('UpdateUserInfo avatar mutations', () => {
|
|
|
79
79
|
const second = await service.updateAvatarPhoto(png.toString('base64'), 'image/png');
|
|
80
80
|
expect(second.avatarFileId).not.toBe(first.avatarFileId);
|
|
81
81
|
|
|
82
|
-
// The prior file is gone — row and bytes
|
|
82
|
+
// The prior file is gone — row and bytes (the byte store checked directly through the
|
|
83
|
+
// driver: the gated service read now refuses ids with no readable row by design).
|
|
83
84
|
expect(await getFileRow(first.avatarFileId!)).toBeFalsy();
|
|
84
|
-
expect(await
|
|
85
|
+
expect(await FileStorage.getDriver().getFileData(first.avatarFileId!)).toBe('');
|
|
85
86
|
// The new one is intact.
|
|
86
87
|
expect(await getFileRow(second.avatarFileId!)).toBeTruthy();
|
|
87
88
|
});
|