@7365admin1/core 3.67.0 → 3.68.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/CHANGELOG.md +88 -1
- package/dist/index.d.ts +113 -6
- package/dist/index.js +2115 -866
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2524 -1273
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/test/anpr-plate.test.mjs +272 -0
- package/test/dahua-protocol.util.test.mjs +137 -0
- package/test/module-access.test.mjs +27 -0
- package/test/module-gate-kill-switch.test.mjs +48 -0
- package/test/people-create-gate.test.mjs +71 -0
- package/test/socket-session.test.mjs +119 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Proving who is on the other end of a socket.
|
|
3
|
+
*
|
|
4
|
+
* `/manpower` streams every client site's live staffing level — how many guards
|
|
5
|
+
* are actually on shift against how many were promised — to anyone who connects,
|
|
6
|
+
* with no credential of any kind. The authenticated twin `/manpower-live` uses
|
|
7
|
+
* this check; the old namespace is deliberately left open, because the guard app
|
|
8
|
+
* installed on phones today connects to it.
|
|
9
|
+
*
|
|
10
|
+
* Every refusal must look identical. A socket refused because its session
|
|
11
|
+
* expired must not be distinguishable from one refused for sending nothing, or
|
|
12
|
+
* the difference becomes an oracle.
|
|
13
|
+
*/
|
|
14
|
+
import test from "node:test";
|
|
15
|
+
import assert from "node:assert/strict";
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
MANPOWER_LIVE_NAMESPACE,
|
|
19
|
+
authoriseSocketSession,
|
|
20
|
+
sidFromHandshake,
|
|
21
|
+
userIdOfSession,
|
|
22
|
+
} from "./.build/utils/socket-session.util.mjs";
|
|
23
|
+
|
|
24
|
+
const SID = "a-live-session-id";
|
|
25
|
+
const USER = "64b7f0000000000000000007";
|
|
26
|
+
|
|
27
|
+
/** A session store holding exactly one live session. */
|
|
28
|
+
const store = async (sid) => (sid === SID ? { user: USER } : null);
|
|
29
|
+
|
|
30
|
+
test("the authenticated namespace is a NEW one, not the open feed", () => {
|
|
31
|
+
// If this ever became "/manpower", the guard handsets in the field would be
|
|
32
|
+
// cut off the moment it deployed.
|
|
33
|
+
assert.equal(MANPOWER_LIVE_NAMESPACE, "/manpower-live");
|
|
34
|
+
assert.notEqual(MANPOWER_LIVE_NAMESPACE, "/manpower");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("the session id is read from every shape the clients send", () => {
|
|
38
|
+
assert.equal(sidFromHandshake({ headers: { cookie: `a=1; sid=${SID}; b=2` } }), SID);
|
|
39
|
+
assert.equal(sidFromHandshake({ auth: { sid: SID } }), SID);
|
|
40
|
+
assert.equal(sidFromHandshake({ auth: { token: SID } }), SID);
|
|
41
|
+
assert.equal(sidFromHandshake({ headers: { authorization: `Bearer ${SID}` } }), SID);
|
|
42
|
+
assert.equal(sidFromHandshake({ headers: { authorization: SID } }), SID);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("the cookie wins, and an empty one does not mask the auth payload", () => {
|
|
46
|
+
assert.equal(
|
|
47
|
+
sidFromHandshake({ headers: { cookie: `sid=${SID}` }, auth: { sid: "other" } }),
|
|
48
|
+
SID,
|
|
49
|
+
);
|
|
50
|
+
assert.equal(sidFromHandshake({ headers: { cookie: "sid=" }, auth: { sid: SID } }), SID);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("an empty handshake presents nothing", () => {
|
|
54
|
+
assert.equal(sidFromHandshake({}), "");
|
|
55
|
+
assert.equal(sidFromHandshake({ headers: {}, auth: {} }), "");
|
|
56
|
+
assert.equal(sidFromHandshake({ auth: { sid: " " } }), "");
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("a session's user id is read under either spelling", () => {
|
|
60
|
+
assert.equal(userIdOfSession({ user: USER }), USER);
|
|
61
|
+
assert.equal(userIdOfSession({ _id: USER }), USER);
|
|
62
|
+
assert.equal(userIdOfSession(null), "");
|
|
63
|
+
assert.equal(userIdOfSession({}), "");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("a live session is admitted", async () => {
|
|
67
|
+
assert.equal(await authoriseSocketSession({ auth: { sid: SID } }, store), USER);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("an anonymous socket is refused - the whole point of the new namespace", async () => {
|
|
71
|
+
await assert.rejects(() => authoriseSocketSession({}, store), /Unauthorized/);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("an expired or invented session id is refused", async () => {
|
|
75
|
+
await assert.rejects(
|
|
76
|
+
() => authoriseSocketSession({ auth: { sid: "not-real" } }, store),
|
|
77
|
+
/Unauthorized/,
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("a session that resolves to nobody is refused", async () => {
|
|
82
|
+
await assert.rejects(
|
|
83
|
+
() => authoriseSocketSession({ auth: { sid: SID } }, async () => ({})),
|
|
84
|
+
/Unauthorized/,
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test("a session store that is DOWN refuses, it does not let everyone in", async () => {
|
|
89
|
+
// Fail closed here: this is an authentication decision, not a feature flag.
|
|
90
|
+
await assert.rejects(
|
|
91
|
+
() =>
|
|
92
|
+
authoriseSocketSession({ auth: { sid: SID } }, async () => {
|
|
93
|
+
throw new Error("redis is unreachable");
|
|
94
|
+
}),
|
|
95
|
+
/Unauthorized/,
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("every refusal carries the SAME message", async () => {
|
|
100
|
+
const messages = [];
|
|
101
|
+
for (const [handshake, read] of [
|
|
102
|
+
[{}, store],
|
|
103
|
+
[{ auth: { sid: "not-real" } }, store],
|
|
104
|
+
[{ auth: { sid: SID } }, async () => ({})],
|
|
105
|
+
[
|
|
106
|
+
{ auth: { sid: SID } },
|
|
107
|
+
async () => {
|
|
108
|
+
throw new Error("redis is unreachable");
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
]) {
|
|
112
|
+
await authoriseSocketSession(handshake, read).catch((error) =>
|
|
113
|
+
messages.push(error.message),
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
assert.equal(messages.length, 4);
|
|
118
|
+
assert.deepEqual([...new Set(messages)], ["Unauthorized"]);
|
|
119
|
+
});
|