@prosopo/database 3.14.0 → 3.14.2

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.
Files changed (26) hide show
  1. package/.turbo/turbo-build$colon$cjs.log +4 -4
  2. package/.turbo/turbo-build$colon$tsc.log +16 -16
  3. package/.turbo/turbo-build.log +5 -5
  4. package/CHANGELOG.md +45 -0
  5. package/dist/cjs/databases/captcha.cjs +51 -5
  6. package/dist/cjs/databases/provider.cjs +96 -31
  7. package/dist/databases/captcha.d.ts +2 -0
  8. package/dist/databases/captcha.d.ts.map +1 -1
  9. package/dist/databases/captcha.js +51 -5
  10. package/dist/databases/captcha.js.map +1 -1
  11. package/dist/databases/provider.d.ts.map +1 -1
  12. package/dist/databases/provider.js +96 -31
  13. package/dist/databases/provider.js.map +1 -1
  14. package/dist/tests/integration/providedIpPipelineCast.integration.test.d.ts +2 -0
  15. package/dist/tests/integration/providedIpPipelineCast.integration.test.d.ts.map +1 -0
  16. package/dist/tests/integration/providedIpPipelineCast.integration.test.js +139 -0
  17. package/dist/tests/integration/providedIpPipelineCast.integration.test.js.map +1 -0
  18. package/dist/tests/integration/randomSamplingPerformance.integration.test.d.ts +2 -0
  19. package/dist/tests/integration/randomSamplingPerformance.integration.test.d.ts.map +1 -0
  20. package/dist/tests/integration/randomSamplingPerformance.integration.test.js +248 -0
  21. package/dist/tests/integration/randomSamplingPerformance.integration.test.js.map +1 -0
  22. package/dist/tests/integration/sessionRecordProjection.integration.test.d.ts +2 -0
  23. package/dist/tests/integration/sessionRecordProjection.integration.test.d.ts.map +1 -0
  24. package/dist/tests/integration/sessionRecordProjection.integration.test.js +156 -0
  25. package/dist/tests/integration/sessionRecordProjection.integration.test.js.map +1 -0
  26. package/package.json +10 -9
@@ -0,0 +1,139 @@
1
+ import { LogLevel, getLogger } from "@prosopo/logger";
2
+ import { CaptchaStatus, IpAddressType } from "@prosopo/types";
3
+ import { UserCommitmentRecordSchema, } from "@prosopo/types-database";
4
+ import { Long } from "bson";
5
+ import { MongoMemoryServer } from "mongodb-memory-server";
6
+ import { afterAll, beforeAll, describe, expect, it } from "vitest";
7
+ import { MongoMemoryDatabase } from "../../base/mongoMemory.js";
8
+ import { CaptchaDatabase } from "../../databases/captcha.js";
9
+ const logger = getLogger(LogLevel.enum.error, "providedIpPipelineCast.test");
10
+ const IP_V4_LOWER = 16909060n;
11
+ const IP_V6_LOWER_UNSAFE = BigInt("0xB496D250E5C58459");
12
+ const isBsonLong = (v) => v instanceof Long ||
13
+ (typeof v === "object" &&
14
+ v !== null &&
15
+ "_bsontype" in v &&
16
+ v._bsontype === "Long");
17
+ describe("updateDappUserCommitment pipeline cast on providedIp.lower", () => {
18
+ let mongoDb;
19
+ let CommitmentModel;
20
+ beforeAll(async () => {
21
+ mongoDb = new MongoMemoryDatabase("ignored", "captchastorage", logger);
22
+ await mongoDb.connect();
23
+ if (!mongoDb.connection) {
24
+ throw new Error("MongoMemoryDatabase failed to provide a connection");
25
+ }
26
+ CommitmentModel = mongoDb.connection.model("Commitment", UserCommitmentRecordSchema);
27
+ });
28
+ afterAll(async () => {
29
+ await mongoDb.close();
30
+ });
31
+ const seedCommitment = async (id) => {
32
+ await CommitmentModel.create({
33
+ id,
34
+ userAccount: "userTest",
35
+ dappAccount: "dappTest",
36
+ providerAccount: "providerTest",
37
+ datasetId: "datasetTest",
38
+ result: { status: CaptchaStatus.pending },
39
+ userSignature: "0xsig",
40
+ ipAddress: { lower: IP_V4_LOWER, type: IpAddressType.v4 },
41
+ headers: { host: "pronode-test.local" },
42
+ ja4: "ja4-test",
43
+ userSubmitted: false,
44
+ serverChecked: false,
45
+ requestedAtTimestamp: new Date(),
46
+ pending: false,
47
+ salt: "salt",
48
+ requestHash: "0xreqhash",
49
+ deadlineTimestamp: new Date(Date.now() + 60_000),
50
+ threshold: 0.5,
51
+ });
52
+ };
53
+ it("writes providedIp.lower as Decimal128 (not Long) via the fixed updateDappUserCommitment path (IPv6 case from production)", async () => {
54
+ const id = "commitment-pipeline-v6";
55
+ await seedCommitment(id);
56
+ const timestamp = new Date();
57
+ await CommitmentModel.updateOne({ id }, {
58
+ $set: {
59
+ providedIp: {
60
+ lower: IP_V6_LOWER_UNSAFE,
61
+ upper: IP_V6_LOWER_UNSAFE,
62
+ type: IpAddressType.v6,
63
+ },
64
+ lastUpdatedAtTimestamp: timestamp,
65
+ pendingStage: true,
66
+ },
67
+ });
68
+ const stored = await CommitmentModel.findOne({ id }).lean();
69
+ expect(stored).not.toBeNull();
70
+ if (!stored?.providedIp)
71
+ throw new Error("providedIp was not persisted");
72
+ expect(stored.providedIp.type).toBe(IpAddressType.v6);
73
+ expect(isBsonLong(stored.providedIp.lower), "providedIp.lower was persisted as BSON Long — schema setter didn't run on this write").toBe(false);
74
+ expect(isBsonLong(stored.providedIp.upper), "providedIp.upper was persisted as BSON Long — same root cause").toBe(false);
75
+ const lower = stored.providedIp.lower;
76
+ expect(lower?._bsontype).toBe("Decimal128");
77
+ });
78
+ it("the *pipeline* form of the same write still produces a Long on disk — this is the original bug, kept as a negative control", async () => {
79
+ const id = "commitment-pipeline-v6-negative-control";
80
+ await seedCommitment(id);
81
+ await CommitmentModel.updateOne({ id }, [
82
+ {
83
+ $set: {
84
+ providedIp: {
85
+ lower: IP_V6_LOWER_UNSAFE,
86
+ upper: IP_V6_LOWER_UNSAFE,
87
+ type: IpAddressType.v6,
88
+ },
89
+ },
90
+ },
91
+ ]);
92
+ const stored = await CommitmentModel.findOne({ id }).lean();
93
+ expect(stored?.providedIp).toBeDefined();
94
+ expect(isBsonLong(stored?.providedIp?.lower)).toBe(true);
95
+ });
96
+ it("the central-streaming sweep replays a Long-typed providedIp.lower without aborting (via CaptchaDatabase.saveCaptchas normalisation)", async () => {
97
+ const id = "commitment-pipeline-v6-sweep";
98
+ await seedCommitment(id);
99
+ await CommitmentModel.updateOne({ id }, [
100
+ {
101
+ $set: {
102
+ providedIp: {
103
+ lower: IP_V6_LOWER_UNSAFE,
104
+ upper: IP_V6_LOWER_UNSAFE,
105
+ type: IpAddressType.v6,
106
+ },
107
+ },
108
+ },
109
+ ]);
110
+ const poisoned = await CommitmentModel.findOne({ id }).lean();
111
+ expect(poisoned).not.toBeNull();
112
+ if (!poisoned?.providedIp)
113
+ return;
114
+ expect(isBsonLong(poisoned.providedIp.lower)).toBe(true);
115
+ const centralMongod = await MongoMemoryServer.create();
116
+ const central = new CaptchaDatabase(centralMongod.getUri(), "captchastorage", undefined, logger);
117
+ try {
118
+ await central.saveCaptchas([], [poisoned], []);
119
+ await central.connect();
120
+ const replayed = await central.tables.commitment
121
+ .findOne({ id })
122
+ .lean();
123
+ expect(replayed).not.toBeNull();
124
+ if (!replayed?.providedIp) {
125
+ throw new Error("central commitment doc missing providedIp");
126
+ }
127
+ expect(isBsonLong(replayed.providedIp.lower), "providedIp.lower at central is still Long — saveCaptchas didn't normalise").toBe(false);
128
+ expect(replayed.providedIp.lower?._bsontype).toBe("Decimal128");
129
+ const expected = IP_V6_LOWER_UNSAFE.toString();
130
+ const got = String(replayed.providedIp.lower);
131
+ expect(got).toBe(expected);
132
+ }
133
+ finally {
134
+ await central.close();
135
+ await centralMongod.stop();
136
+ }
137
+ });
138
+ });
139
+ //# sourceMappingURL=providedIpPipelineCast.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providedIpPipelineCast.integration.test.js","sourceRoot":"","sources":["../../../src/tests/integration/providedIpPipelineCast.integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=randomSamplingPerformance.integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"randomSamplingPerformance.integration.test.d.ts","sourceRoot":"","sources":["../../../src/tests/integration/randomSamplingPerformance.integration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,248 @@
1
+ import { LogLevel, getLogger } from "@prosopo/logger";
2
+ import { CaptchaStatus, ContextType, IpAddressType, } from "@prosopo/types";
3
+ import { CaptchaRecordSchema, PoWCaptchaRecordSchema, SessionRecordSchema, } from "@prosopo/types-database";
4
+ import { afterAll, beforeAll, describe, expect, it } from "vitest";
5
+ import { MongoMemoryDatabase } from "../../base/mongoMemory.js";
6
+ const logger = getLogger(LogLevel.enum.error, "randomSamplingPerformance.test");
7
+ const TWENTY_FOUR_HOURS_IN_MS = 24 * 60 * 60 * 1000;
8
+ function getStats(explain) {
9
+ if (explain?.executionStats)
10
+ return explain.executionStats;
11
+ const cursor = explain?.stages?.[0]?.$cursor;
12
+ return cursor?.executionStats;
13
+ }
14
+ async function timeIt(fn, iterations) {
15
+ await fn();
16
+ const start = process.hrtime.bigint();
17
+ for (let i = 0; i < iterations; i++) {
18
+ await fn();
19
+ }
20
+ const end = process.hrtime.bigint();
21
+ return Number(end - start) / 1_000_000 / iterations;
22
+ }
23
+ describe("getRandomCaptcha — randomKey range scan vs $sample aggregation", () => {
24
+ let mongoDb;
25
+ let CaptchaModel;
26
+ const datasetId = "0xdeadbeefcafef00ddeadbeefcafef00ddeadbeefcafef00ddeadbeefcafef00d";
27
+ const SOLVED_COUNT = 5000;
28
+ const SAMPLE_SIZE = 2;
29
+ beforeAll(async () => {
30
+ mongoDb = new MongoMemoryDatabase("ignored", "captchaperf", logger);
31
+ await mongoDb.connect();
32
+ if (!mongoDb.connection) {
33
+ throw new Error("MongoMemoryDatabase failed to provide a connection");
34
+ }
35
+ CaptchaModel = mongoDb.connection.model("Captcha", CaptchaRecordSchema);
36
+ await CaptchaModel.syncIndexes();
37
+ const docs = Array.from({ length: SOLVED_COUNT }, (_, i) => ({
38
+ captchaId: `cap-${i}`,
39
+ captchaContentId: `content-${i}`,
40
+ datasetId,
41
+ datasetContentId: `dc-${i}`,
42
+ solved: true,
43
+ target: "find the cars",
44
+ salt: "0xsalt",
45
+ items: [{ hash: `h-${i}`, data: "d", type: "image" }],
46
+ randomKey: Math.random(),
47
+ }));
48
+ await CaptchaModel.insertMany(docs);
49
+ }, 60_000);
50
+ afterAll(async () => {
51
+ await mongoDb.close();
52
+ });
53
+ it("range scan over the compound index examines O(sampleSize) keys, not O(pool)", async () => {
54
+ const pivot = Math.random();
55
+ const newExplain = await CaptchaModel.find({ datasetId, solved: true, randomKey: { $gte: pivot } }, { _id: 0, captchaId: 1 })
56
+ .sort({ randomKey: 1 })
57
+ .limit(SAMPLE_SIZE)
58
+ .explain("executionStats");
59
+ const newStats = getStats(newExplain);
60
+ if (!newStats)
61
+ throw new Error("explain returned no stats for the new path");
62
+ const oldExplain = await CaptchaModel.aggregate([
63
+ { $match: { datasetId, solved: true } },
64
+ { $sample: { size: SAMPLE_SIZE } },
65
+ { $project: { captchaId: 1 } },
66
+ ]).explain("executionStats");
67
+ const oldStats = getStats(oldExplain);
68
+ if (!oldStats)
69
+ throw new Error("explain returned no stats for the old path");
70
+ expect(newStats.nReturned).toBeGreaterThan(0);
71
+ expect(newStats.totalKeysExamined).toBeLessThanOrEqual(SAMPLE_SIZE * 4);
72
+ expect(newStats.totalKeysExamined * 10).toBeLessThan(oldStats.totalKeysExamined);
73
+ });
74
+ it("range scan is faster on the wall clock than the $sample aggregation", async () => {
75
+ const iterations = 20;
76
+ const newAvgMs = await timeIt(async () => {
77
+ const pivot = Math.random();
78
+ const head = await CaptchaModel.find({ datasetId, solved: true, randomKey: { $gte: pivot } }, { _id: 0, captchaId: 1, items: 1, target: 1 })
79
+ .sort({ randomKey: 1 })
80
+ .limit(SAMPLE_SIZE)
81
+ .lean();
82
+ if (head.length < SAMPLE_SIZE) {
83
+ await CaptchaModel.find({ datasetId, solved: true, randomKey: { $lt: pivot } }, { _id: 0, captchaId: 1, items: 1, target: 1 })
84
+ .sort({ randomKey: 1 })
85
+ .limit(SAMPLE_SIZE - head.length)
86
+ .lean();
87
+ }
88
+ }, iterations);
89
+ const oldAvgMs = await timeIt(async () => {
90
+ await CaptchaModel.aggregate([
91
+ { $match: { datasetId, solved: true } },
92
+ { $sample: { size: SAMPLE_SIZE } },
93
+ {
94
+ $project: {
95
+ captchaId: 1,
96
+ items: 1,
97
+ target: 1,
98
+ },
99
+ },
100
+ ]).exec();
101
+ }, iterations);
102
+ logger.info(() => ({
103
+ msg: "getRandomCaptcha timing",
104
+ data: { newAvgMs, oldAvgMs, ratio: oldAvgMs / newAvgMs },
105
+ }));
106
+ expect(newAvgMs).toBeLessThan(oldAvgMs);
107
+ expect(oldAvgMs / newAvgMs).toBeGreaterThan(1.5);
108
+ });
109
+ });
110
+ describe("sampleContextEntropy — $sample before $lookup vs $lookup before $sample", () => {
111
+ let mongoDb;
112
+ let PowModel;
113
+ let SessionModel;
114
+ const siteKey = "5FWoE4Z7K24tKXxccQpaAKXThnYwndgqCr2jmiytT4VVbiwG";
115
+ const POW_COUNT = 6000;
116
+ const SAMPLE_SIZE = 75;
117
+ const MAX = 2000;
118
+ beforeAll(async () => {
119
+ mongoDb = new MongoMemoryDatabase("ignored", "powperf", logger);
120
+ await mongoDb.connect();
121
+ if (!mongoDb.connection) {
122
+ throw new Error("MongoMemoryDatabase failed to provide a connection");
123
+ }
124
+ PowModel = mongoDb.connection.model("PowCaptcha", PoWCaptchaRecordSchema);
125
+ SessionModel = mongoDb.connection.model("Session", SessionRecordSchema);
126
+ await PowModel.syncIndexes();
127
+ await SessionModel.syncIndexes();
128
+ const now = Date.now();
129
+ const powDocs = [];
130
+ const sessionDocs = [];
131
+ for (let i = 0; i < POW_COUNT; i++) {
132
+ const sessionId = `session-${i}`;
133
+ powDocs.push({
134
+ challenge: `challenge-${i}`,
135
+ dappAccount: siteKey,
136
+ userAccount: `user-${i}`,
137
+ requestedAtTimestamp: new Date(now - i * 60),
138
+ result: { status: CaptchaStatus.approved },
139
+ difficulty: 1,
140
+ ipAddress: { lower: BigInt(i + 1).toString(), type: IpAddressType.v4 },
141
+ headers: { host: "pronode-test.local" },
142
+ ja4: "ja4",
143
+ userSubmitted: false,
144
+ serverChecked: false,
145
+ providerSignature: "0xsig",
146
+ sessionId,
147
+ });
148
+ sessionDocs.push({
149
+ sessionId,
150
+ webView: i % 2 === 0,
151
+ captchaType: "pow",
152
+ createdAt: new Date(now - i * 60),
153
+ });
154
+ }
155
+ await PowModel.insertMany(powDocs);
156
+ const sessionsCollection = mongoDb.connection.collection("sessions");
157
+ await sessionsCollection.insertMany(sessionDocs);
158
+ }, 60_000);
159
+ afterAll(async () => {
160
+ await mongoDb.close();
161
+ });
162
+ const newPipeline = (contextType) => {
163
+ const stages = [
164
+ {
165
+ $match: {
166
+ dappAccount: siteKey,
167
+ requestedAtTimestamp: {
168
+ $gt: new Date(Date.now() - TWENTY_FOUR_HOURS_IN_MS),
169
+ },
170
+ },
171
+ },
172
+ { $sample: { size: MAX } },
173
+ {
174
+ $lookup: {
175
+ from: "sessions",
176
+ localField: "sessionId",
177
+ foreignField: "sessionId",
178
+ as: "sessionData",
179
+ },
180
+ },
181
+ {
182
+ $unwind: { path: "$sessionData", preserveNullAndEmptyArrays: false },
183
+ },
184
+ ];
185
+ if (contextType === ContextType.Default) {
186
+ stages.push({ $match: { "sessionData.webView": false } });
187
+ }
188
+ stages.push({ $sample: { size: SAMPLE_SIZE } }, { $project: { _id: 0, sessionId: 1 } });
189
+ return stages;
190
+ };
191
+ const oldPipeline = (contextType) => {
192
+ const stages = [
193
+ {
194
+ $match: {
195
+ dappAccount: siteKey,
196
+ requestedAtTimestamp: {
197
+ $gt: new Date(Date.now() - TWENTY_FOUR_HOURS_IN_MS),
198
+ },
199
+ },
200
+ },
201
+ {
202
+ $lookup: {
203
+ from: "sessions",
204
+ localField: "sessionId",
205
+ foreignField: "sessionId",
206
+ as: "sessionData",
207
+ },
208
+ },
209
+ {
210
+ $unwind: { path: "$sessionData", preserveNullAndEmptyArrays: false },
211
+ },
212
+ ];
213
+ if (contextType === ContextType.Default) {
214
+ stages.push({ $match: { "sessionData.webView": false } });
215
+ }
216
+ stages.push({ $limit: MAX }, { $sample: { size: SAMPLE_SIZE } }, { $project: { _id: 0, sessionId: 1 } });
217
+ return stages;
218
+ };
219
+ it("new ordering returns the requested sample size", async () => {
220
+ const docs = await PowModel.aggregate(newPipeline(ContextType.Default)).exec();
221
+ expect(docs.length).toBeGreaterThan(0);
222
+ expect(docs.length).toBeLessThanOrEqual(SAMPLE_SIZE);
223
+ });
224
+ it("new ordering is faster than the original $lookup-first ordering", async () => {
225
+ const iterations = 10;
226
+ let newTotalNs = 0n;
227
+ let oldTotalNs = 0n;
228
+ await PowModel.aggregate(newPipeline(ContextType.Default)).exec();
229
+ await PowModel.aggregate(oldPipeline(ContextType.Default)).exec();
230
+ for (let i = 0; i < iterations; i++) {
231
+ const t0 = process.hrtime.bigint();
232
+ await PowModel.aggregate(newPipeline(ContextType.Default)).exec();
233
+ const t1 = process.hrtime.bigint();
234
+ await PowModel.aggregate(oldPipeline(ContextType.Default)).exec();
235
+ const t2 = process.hrtime.bigint();
236
+ newTotalNs += t1 - t0;
237
+ oldTotalNs += t2 - t1;
238
+ }
239
+ const newAvgMs = Number(newTotalNs) / iterations / 1_000_000;
240
+ const oldAvgMs = Number(oldTotalNs) / iterations / 1_000_000;
241
+ logger.info(() => ({
242
+ msg: "sampleContextEntropy timing",
243
+ data: { newAvgMs, oldAvgMs, ratio: oldAvgMs / newAvgMs },
244
+ }));
245
+ expect(oldAvgMs / newAvgMs).toBeGreaterThan(1.3);
246
+ });
247
+ });
248
+ //# sourceMappingURL=randomSamplingPerformance.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"randomSamplingPerformance.integration.test.js","sourceRoot":"","sources":["../../../src/tests/integration/randomSamplingPerformance.integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sessionRecordProjection.integration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessionRecordProjection.integration.test.d.ts","sourceRoot":"","sources":["../../../src/tests/integration/sessionRecordProjection.integration.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,156 @@
1
+ import { LogLevel, getLogger } from "@prosopo/logger";
2
+ import { CaptchaType, IpAddressType, } from "@prosopo/types";
3
+ import { SessionRecordSchema } from "@prosopo/types-database";
4
+ import { MongoMemoryServer } from "mongodb-memory-server";
5
+ import { afterAll, beforeAll, describe, expect, it } from "vitest";
6
+ import { ProviderDatabase } from "../../databases/provider.js";
7
+ const logger = getLogger(LogLevel.enum.error, "sessionRecordProjection.test");
8
+ class TestProviderDatabase extends ProviderDatabase {
9
+ async setupRedis() {
10
+ }
11
+ }
12
+ const ipv4Composite = (lower) => ({
13
+ lower,
14
+ type: IpAddressType.v4,
15
+ });
16
+ describe("getSessionRecordBySessionId projection", () => {
17
+ let mongod;
18
+ let db;
19
+ beforeAll(async () => {
20
+ mongod = await MongoMemoryServer.create();
21
+ db = new TestProviderDatabase({
22
+ mongo: { url: mongod.getUri(), dbname: "captchastorage" },
23
+ logger,
24
+ });
25
+ await db.connect();
26
+ });
27
+ afterAll(async () => {
28
+ await db.close();
29
+ await mongod.stop();
30
+ });
31
+ it("round-trips every field buildEscalation forwards into createSession", async () => {
32
+ const sessionId = "session-projection-roundtrip";
33
+ const createdAt = new Date();
34
+ const ipAddress = ipv4Composite(16843009n);
35
+ await db.tables.session.create({
36
+ sessionId,
37
+ createdAt,
38
+ token: "tok-roundtrip",
39
+ score: 0.42,
40
+ threshold: 0.5,
41
+ scoreComponents: { baseScore: 0.42, lScore: 0.1 },
42
+ providerSelectEntropy: 0.7,
43
+ ipAddress,
44
+ captchaType: CaptchaType.pow,
45
+ mode: undefined,
46
+ solvedImagesCount: 3,
47
+ userSitekeyIpHash: "hash-abc",
48
+ webView: true,
49
+ iFrame: false,
50
+ decryptedHeadHash: "head-hash-xyz",
51
+ siteKey: "site-key-1",
52
+ reason: "user-passed",
53
+ headers: {
54
+ "user-agent": "Mozilla/5.0",
55
+ "accept-language": "en-GB",
56
+ "x-tls-clienthello": "AAAAAAAAAAAAAA==".repeat(200),
57
+ },
58
+ });
59
+ const got = await db.getSessionRecordBySessionId(sessionId);
60
+ expect(got).toBeDefined();
61
+ if (!got)
62
+ throw new Error("session not returned");
63
+ expect(got.token).toBe("tok-roundtrip");
64
+ expect(got.score).toBe(0.42);
65
+ expect(got.threshold).toBe(0.5);
66
+ expect(got.providerSelectEntropy).toBe(0.7);
67
+ expect(got.ipAddress).toBeDefined();
68
+ expect(got.ipAddress?.type).toBe(IpAddressType.v4);
69
+ expect(got.ipAddress?.lower).toBeDefined();
70
+ expect(got.siteKey).toBe("site-key-1");
71
+ expect(got.solvedImagesCount).toBe(3);
72
+ expect(got.userSitekeyIpHash).toBe("hash-abc");
73
+ expect(got.scoreComponents?.baseScore).toBe(0.42);
74
+ expect(got.webView).toBe(true);
75
+ expect(got.iFrame).toBe(false);
76
+ expect(got.decryptedHeadHash).toBe("head-hash-xyz");
77
+ expect(got.reason).toBe("user-passed");
78
+ expect(got.headers?.["user-agent"]).toBe("Mozilla/5.0");
79
+ expect(got.headers?.["accept-language"]).toBe("en-GB");
80
+ expect(got.headers?.["x-tls-clienthello"]).toBeUndefined();
81
+ });
82
+ it("a session read via getSessionRecordBySessionId can be re-persisted as a new escalation session", async () => {
83
+ const originSessionId = "session-escalation-origin";
84
+ await db.tables.session.create({
85
+ sessionId: originSessionId,
86
+ createdAt: new Date(),
87
+ token: "tok-escalation",
88
+ score: 0.6,
89
+ threshold: 0.5,
90
+ scoreComponents: { baseScore: 0.6 },
91
+ providerSelectEntropy: 0.3,
92
+ ipAddress: ipv4Composite(16843009n),
93
+ captchaType: CaptchaType.pow,
94
+ webView: false,
95
+ iFrame: false,
96
+ decryptedHeadHash: "head-escalation",
97
+ siteKey: "site-key-escalation",
98
+ });
99
+ const origin = await db.getSessionRecordBySessionId(originSessionId);
100
+ if (!origin)
101
+ throw new Error("origin session not returned");
102
+ await expect(db.tables.session.create({
103
+ sessionId: "session-escalation-new",
104
+ createdAt: new Date(),
105
+ token: origin.token,
106
+ score: origin.score,
107
+ threshold: origin.threshold,
108
+ scoreComponents: origin.scoreComponents,
109
+ providerSelectEntropy: origin.providerSelectEntropy,
110
+ ipAddress: origin.ipAddress,
111
+ captchaType: CaptchaType.image,
112
+ webView: origin.webView,
113
+ iFrame: origin.iFrame,
114
+ decryptedHeadHash: origin.decryptedHeadHash,
115
+ siteKey: origin.siteKey,
116
+ })).resolves.toBeDefined();
117
+ });
118
+ it("every required Session schema field is included in the projection", async () => {
119
+ const requiredPathsWithoutDefault = Object.entries(SessionRecordSchema.paths)
120
+ .filter(([, pathSchema]) => {
121
+ const p = pathSchema;
122
+ return p.isRequired === true && p.defaultValue === undefined;
123
+ })
124
+ .map(([name]) => name);
125
+ expect(requiredPathsWithoutDefault).toEqual(expect.arrayContaining([
126
+ "token",
127
+ "score",
128
+ "threshold",
129
+ "providerSelectEntropy",
130
+ ]));
131
+ const sessionId = "session-required-fields";
132
+ await db.tables.session.create({
133
+ sessionId,
134
+ createdAt: new Date(),
135
+ token: "tok-required",
136
+ score: 0.1,
137
+ threshold: 0.2,
138
+ scoreComponents: { baseScore: 0.1 },
139
+ providerSelectEntropy: 0.4,
140
+ ipAddress: ipv4Composite(16843009n),
141
+ captchaType: CaptchaType.pow,
142
+ webView: false,
143
+ iFrame: false,
144
+ });
145
+ const got = await db.getSessionRecordBySessionId(sessionId);
146
+ if (!got)
147
+ throw new Error("session not returned");
148
+ const forwardedRequiredFields = requiredPathsWithoutDefault.filter((p) => p !== "createdAt" && p !== "captchaType" && p !== "sessionId");
149
+ const gotRecord = got;
150
+ for (const path of forwardedRequiredFields) {
151
+ const top = path.split(".")[0] ?? path;
152
+ expect(gotRecord[top], `required Session field '${top}' (from schema path '${path}') was missing from the projection — extend getSessionRecordBySessionId`).toBeDefined();
153
+ }
154
+ });
155
+ });
156
+ //# sourceMappingURL=sessionRecordProjection.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sessionRecordProjection.integration.test.js","sourceRoot":"","sources":["../../../src/tests/integration/sessionRecordProjection.integration.test.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EACN,WAAW,EAEX,aAAa,GACb,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAuC/D,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,8BAA8B,CAAC,CAAC;AAK9E,MAAM,oBAAqB,SAAQ,gBAAgB;IAC/B,KAAK,CAAC,UAAU;IAEnC,CAAC;CACD;AAED,MAAM,aAAa,GAAG,CAAC,KAAa,EAAsB,EAAE,CAAC,CAAC;IAC7D,KAAK;IACL,IAAI,EAAE,aAAa,CAAC,EAAE;CACtB,CAAC,CAAC;AAEH,QAAQ,CAAC,wCAAwC,EAAE,GAAG,EAAE;IACvD,IAAI,MAAyB,CAAC;IAC9B,IAAI,EAAwB,CAAC;IAE7B,SAAS,CAAC,KAAK,IAAI,EAAE;QACpB,MAAM,GAAG,MAAM,iBAAiB,CAAC,MAAM,EAAE,CAAC;QAC1C,EAAE,GAAG,IAAI,oBAAoB,CAAC;YAC7B,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,gBAAgB,EAAE;YACzD,MAAM;SACN,CAAC,CAAC;QACH,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,KAAK,IAAI,EAAE;QACpF,MAAM,SAAS,GAAG,8BAA8B,CAAC;QACjD,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;QAC7B,MAAM,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;QAE3C,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;YAC9B,SAAS;YACT,SAAS;YACT,KAAK,EAAE,eAAe;YACtB,KAAK,EAAE,IAAI;YACX,SAAS,EAAE,GAAG;YACd,eAAe,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;YACjD,qBAAqB,EAAE,GAAG;YAC1B,SAAS;YACT,WAAW,EAAE,WAAW,CAAC,GAAG;YAC5B,IAAI,EAAE,SAAS;YACf,iBAAiB,EAAE,CAAC;YACpB,iBAAiB,EAAE,UAAU;YAC7B,OAAO,EAAE,IAAI;YACb,MAAM,EAAE,KAAK;YACb,iBAAiB,EAAE,eAAe;YAClC,OAAO,EAAE,YAAY;YACrB,MAAM,EAAE,aAAa;YACrB,OAAO,EAAE;gBACR,YAAY,EAAE,aAAa;gBAC3B,iBAAiB,EAAE,OAAO;gBAG1B,mBAAmB,EAAE,kBAAkB,CAAC,MAAM,CAAC,GAAG,CAAC;aACnD;SACD,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,2BAA2B,CAAC,SAAS,CAAC,CAAC;QAE5D,MAAM,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;QAC1B,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAKlD,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACxC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC5C,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;QACpC,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACnD,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;QAM3C,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACvC,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC/C,MAAM,CAAC,GAAG,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/B,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACpD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAKvC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACxD,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvD,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,mBAAmB,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IAC5D,CAAC,CAAC,CAAC;IAUH,EAAE,CAAC,gGAAgG,EAAE,KAAK,IAAI,EAAE;QAC/G,MAAM,eAAe,GAAG,2BAA2B,CAAC;QACpD,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;YAC9B,SAAS,EAAE,eAAe;YAC1B,SAAS,EAAE,IAAI,IAAI,EAAE;YACrB,KAAK,EAAE,gBAAgB;YACvB,KAAK,EAAE,GAAG;YACV,SAAS,EAAE,GAAG;YACd,eAAe,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE;YACnC,qBAAqB,EAAE,GAAG;YAC1B,SAAS,EAAE,aAAa,CAAC,SAAS,CAAC;YACnC,WAAW,EAAE,WAAW,CAAC,GAAG;YAC5B,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,KAAK;YACb,iBAAiB,EAAE,iBAAiB;YACpC,OAAO,EAAE,qBAAqB;SAC9B,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,2BAA2B,CAAC,eAAe,CAAC,CAAC;QACrE,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QAM5D,MAAM,MAAM,CACX,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;YACxB,SAAS,EAAE,wBAAwB;YACnC,SAAS,EAAE,IAAI,IAAI,EAAE;YACrB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,eAAe,EAAE,MAAM,CAAC,eAAe;YACvC,qBAAqB,EAAE,MAAM,CAAC,qBAAqB;YACnD,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,WAAW,EAAE,WAAW,CAAC,KAAK;YAC9B,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,iBAAiB,EAAE,MAAM,CAAC,iBAAiB;YAC3C,OAAO,EAAE,MAAM,CAAC,OAAO;SACvB,CAAC,CACF,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAQH,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QAIlF,MAAM,2BAA2B,GAAG,MAAM,CAAC,OAAO,CACjD,mBAAmB,CAAC,KAAK,CACzB;aACC,MAAM,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,EAAE;YAC1B,MAAM,CAAC,GAAG,UAGT,CAAC;YACF,OAAO,CAAC,CAAC,UAAU,KAAK,IAAI,IAAI,CAAC,CAAC,YAAY,KAAK,SAAS,CAAC;QAC9D,CAAC,CAAC;aACD,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;QAGxB,MAAM,CAAC,2BAA2B,CAAC,CAAC,OAAO,CAC1C,MAAM,CAAC,eAAe,CAAC;YACtB,OAAO;YACP,OAAO;YACP,WAAW;YACX,uBAAuB;SACvB,CAAC,CACF,CAAC;QAEF,MAAM,SAAS,GAAG,yBAAyB,CAAC;QAC5C,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;YAC9B,SAAS;YACT,SAAS,EAAE,IAAI,IAAI,EAAE;YACrB,KAAK,EAAE,cAAc;YACrB,KAAK,EAAE,GAAG;YACV,SAAS,EAAE,GAAG;YACd,eAAe,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE;YACnC,qBAAqB,EAAE,GAAG;YAC1B,SAAS,EAAE,aAAa,CAAC,SAAS,CAAC;YACnC,WAAW,EAAE,WAAW,CAAC,GAAG;YAC5B,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,KAAK;SACb,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,2BAA2B,CAAC,SAAS,CAAC,CAAC;QAC5D,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAOlD,MAAM,uBAAuB,GAAG,2BAA2B,CAAC,MAAM,CACjE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,aAAa,IAAI,CAAC,KAAK,WAAW,CACpE,CAAC;QAEF,MAAM,SAAS,GAAG,GAAyC,CAAC;QAC5D,KAAK,MAAM,IAAI,IAAI,uBAAuB,EAAE,CAAC;YAI5C,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;YACvC,MAAM,CACL,SAAS,CAAC,GAAG,CAAC,EACd,2BAA2B,GAAG,wBAAwB,IAAI,yEAAyE,CACnI,CAAC,WAAW,EAAE,CAAC;QACjB,CAAC;IACF,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prosopo/database",
3
- "version": "3.14.0",
3
+ "version": "3.14.2",
4
4
  "description": "Prosopo database plugins for provider",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -38,20 +38,21 @@
38
38
  "homepage": "https://github.com/prosopo/captcha#readme",
39
39
  "dependencies": {
40
40
  "@polkadot/util": "13.5.7",
41
- "@prosopo/common": "3.1.38",
42
- "@prosopo/logger": "1.0.2",
43
- "@prosopo/redis-client": "1.0.23",
44
- "@prosopo/types": "4.5.0",
45
- "@prosopo/types-database": "4.10.0",
46
- "@prosopo/user-access-policy": "3.10.0",
47
- "@prosopo/util": "3.2.15",
41
+ "@prosopo/common": "3.1.39",
42
+ "@prosopo/logger": "1.0.3",
43
+ "@prosopo/redis-client": "1.0.24",
44
+ "@prosopo/types": "4.6.1",
45
+ "@prosopo/types-database": "4.10.2",
46
+ "@prosopo/user-access-policy": "3.10.2",
47
+ "@prosopo/util": "3.3.0",
48
+ "bson": "6.10.4",
48
49
  "make-dir": "3.1.0",
49
50
  "mongodb": "6.15.0",
50
51
  "mongodb-memory-server": "10.3.0",
51
52
  "mongoose": "8.13.0"
52
53
  },
53
54
  "devDependencies": {
54
- "@prosopo/config": "3.3.1",
55
+ "@prosopo/config": "3.3.2",
55
56
  "@types/node": "22.10.2",
56
57
  "@vitest/coverage-v8": "3.2.4",
57
58
  "concurrently": "9.0.1",