@prosopo/database 4.0.16 → 4.0.18

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 +3 -3
  2. package/.turbo/turbo-build$colon$tsc.log +16 -16
  3. package/.turbo/turbo-build.log +4 -4
  4. package/CHANGELOG.md +36 -0
  5. package/dist/cjs/databases/provider.cjs +36 -70
  6. package/dist/databases/provider.d.ts +2 -3
  7. package/dist/databases/provider.d.ts.map +1 -1
  8. package/dist/databases/provider.js +37 -71
  9. package/dist/databases/provider.js.map +1 -1
  10. package/dist/tests/integration/commitmentRecordProjection.integration.test.d.ts +2 -0
  11. package/dist/tests/integration/commitmentRecordProjection.integration.test.d.ts.map +1 -0
  12. package/dist/tests/integration/commitmentRecordProjection.integration.test.js +178 -0
  13. package/dist/tests/integration/commitmentRecordProjection.integration.test.js.map +1 -0
  14. package/dist/tests/integration/projectionContract.d.ts +9 -0
  15. package/dist/tests/integration/projectionContract.d.ts.map +1 -0
  16. package/dist/tests/integration/projectionContract.js +20 -0
  17. package/dist/tests/integration/projectionContract.js.map +1 -0
  18. package/dist/tests/integration/projectionContracts.integration.test.d.ts +2 -0
  19. package/dist/tests/integration/projectionContracts.integration.test.d.ts.map +1 -0
  20. package/dist/tests/integration/projectionContracts.integration.test.js +190 -0
  21. package/dist/tests/integration/projectionContracts.integration.test.js.map +1 -0
  22. package/package.json +9 -9
  23. package/dist/tests/integration/randomSamplingPerformance.integration.test.d.ts +0 -2
  24. package/dist/tests/integration/randomSamplingPerformance.integration.test.d.ts.map +0 -1
  25. package/dist/tests/integration/randomSamplingPerformance.integration.test.js +0 -248
  26. package/dist/tests/integration/randomSamplingPerformance.integration.test.js.map +0 -1
@@ -0,0 +1,190 @@
1
+ import { LogLevel, getLogger } from "@prosopo/logger";
2
+ import { CaptchaStatus, IpAddressType, Tier, } from "@prosopo/types";
3
+ import { MongoMemoryServer } from "mongodb-memory-server";
4
+ import { afterAll, beforeAll, describe } from "vitest";
5
+ import { ProviderDatabase } from "../../databases/provider.js";
6
+ import { testProjectionContract } from "./projectionContract.js";
7
+ const logger = getLogger(LogLevel.enum.error, "projectionContracts.test");
8
+ class TestProviderDatabase extends ProviderDatabase {
9
+ async setupRedis() {
10
+ }
11
+ }
12
+ const ipv4Composite = (lower) => ({
13
+ lower,
14
+ type: IpAddressType.v4,
15
+ });
16
+ const validIpInfo = {
17
+ ip: "203.0.113.1",
18
+ isValid: true,
19
+ isVPN: false,
20
+ isTor: false,
21
+ isProxy: false,
22
+ isDatacenter: false,
23
+ isAbuser: false,
24
+ isMobile: false,
25
+ isSatellite: false,
26
+ isCrawler: false,
27
+ countryCode: "GB",
28
+ asnNumber: 64500,
29
+ abuserScore: 0,
30
+ companyAbuserScore: 0,
31
+ };
32
+ const bdp = () => ({
33
+ c1: [{ x: 100, y: 100, timestamp: 1_787_000_000_000, velocity: 0 }],
34
+ c2: [],
35
+ c3: [
36
+ {
37
+ x: 200,
38
+ y: 200,
39
+ timestamp: 1_787_000_000_500,
40
+ eventType: "click",
41
+ button: 0,
42
+ targetElement: "IMG",
43
+ ctrlKey: false,
44
+ shiftKey: false,
45
+ altKey: false,
46
+ },
47
+ ],
48
+ d: "desktop",
49
+ });
50
+ describe("ProviderDatabase projection contracts", () => {
51
+ let mongod;
52
+ let db;
53
+ beforeAll(async () => {
54
+ mongod = await MongoMemoryServer.create();
55
+ db = new TestProviderDatabase({
56
+ mongo: { url: mongod.getUri(), dbname: "captchastorage" },
57
+ logger,
58
+ });
59
+ await db.connect();
60
+ });
61
+ afterAll(async () => {
62
+ await db.close();
63
+ await mongod.stop();
64
+ });
65
+ testProjectionContract({
66
+ name: "getPowCaptchaRecordByChallenge",
67
+ consumerName: "serverVerifyPowCaptchaSolution",
68
+ insert: async () => {
69
+ const challenge = "1___2___pow-projection-contract";
70
+ const doc = {
71
+ challenge,
72
+ userAccount: "user-pow",
73
+ dappAccount: "dapp-pow",
74
+ requestedAtTimestamp: new Date(),
75
+ submittedAtTimestamp: new Date(),
76
+ ipAddress: ipv4Composite(1n),
77
+ headers: { host: "example.com", "user-agent": "Mozilla/5.0" },
78
+ ja4: "ja4-pow",
79
+ result: { status: CaptchaStatus.approved },
80
+ difficulty: 4,
81
+ providerSignature: "sig-pow",
82
+ sessionId: "session-pow",
83
+ ipInfo: validIpInfo,
84
+ deviceCapability: "desktop",
85
+ behavioralDataPacked: bdp(),
86
+ serverChecked: false,
87
+ userSubmitted: true,
88
+ coords: [[[300, 300]]],
89
+ };
90
+ await db.tables.powcaptcha.create(doc);
91
+ return doc;
92
+ },
93
+ fetch: (fixture) => db.getPowCaptchaRecordByChallenge(fixture.challenge),
94
+ consumerReads: [
95
+ "behavioralDataPacked",
96
+ "challenge",
97
+ "coords",
98
+ "dappAccount",
99
+ "deviceCapability",
100
+ "difficulty",
101
+ "headers",
102
+ "ipAddress",
103
+ "ipInfo",
104
+ "result",
105
+ "serverChecked",
106
+ "sessionId",
107
+ "submittedAtTimestamp",
108
+ "userAccount",
109
+ ],
110
+ });
111
+ testProjectionContract({
112
+ name: "getPuzzleCaptchaRecordByChallenge",
113
+ consumerName: "serverVerifyPuzzleCaptchaSolution",
114
+ insert: async () => {
115
+ const challenge = "1___2___puzzle-projection-contract";
116
+ const doc = {
117
+ challenge,
118
+ userAccount: "user-puzzle",
119
+ dappAccount: "dapp-puzzle",
120
+ requestedAtTimestamp: new Date(),
121
+ submittedAtTimestamp: new Date(),
122
+ ipAddress: ipv4Composite(1n),
123
+ headers: { host: "example.com", "user-agent": "Mozilla/5.0" },
124
+ ja4: "ja4-puzzle",
125
+ result: { status: CaptchaStatus.approved },
126
+ targetX: 100,
127
+ targetY: 100,
128
+ originX: 0,
129
+ originY: 0,
130
+ tolerance: 10,
131
+ puzzleEvents: [
132
+ { x: 10, y: 10, t: 1_787_000_000_000 },
133
+ { x: 100, y: 100, t: 1_787_000_000_500 },
134
+ ],
135
+ providerSignature: "sig-puzzle",
136
+ sessionId: "session-puzzle",
137
+ ipInfo: validIpInfo,
138
+ deviceCapability: "desktop",
139
+ behavioralDataPacked: bdp(),
140
+ serverChecked: false,
141
+ userSubmitted: true,
142
+ coords: [[[100, 100]]],
143
+ };
144
+ await db.tables.puzzlecaptcha.create(doc);
145
+ return doc;
146
+ },
147
+ fetch: (fixture) => db.getPuzzleCaptchaRecordByChallenge(fixture.challenge),
148
+ consumerReads: [
149
+ "behavioralDataPacked",
150
+ "challenge",
151
+ "coords",
152
+ "dappAccount",
153
+ "deviceCapability",
154
+ "headers",
155
+ "ipAddress",
156
+ "ipInfo",
157
+ "puzzleEvents",
158
+ "result",
159
+ "serverChecked",
160
+ "sessionId",
161
+ "submittedAtTimestamp",
162
+ "targetX",
163
+ "targetY",
164
+ "tolerance",
165
+ "userAccount",
166
+ "userSubmitted",
167
+ ],
168
+ });
169
+ testProjectionContract({
170
+ name: "getClientRecord",
171
+ consumerName: "provider tasks (settings/tier readers)",
172
+ insert: async () => {
173
+ const doc = {
174
+ account: "client-projection-contract",
175
+ tier: Tier.Free,
176
+ settings: {
177
+ domains: ["example.com"],
178
+ frictionlessThreshold: 0.5,
179
+ powDifficulty: 4,
180
+ captchaType: "image",
181
+ },
182
+ };
183
+ await db.tables.client.create(doc);
184
+ return doc;
185
+ },
186
+ fetch: (fixture) => db.getClientRecord(fixture.account),
187
+ consumerReads: ["account", "settings", "tier"],
188
+ });
189
+ });
190
+ //# sourceMappingURL=projectionContracts.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectionContracts.integration.test.js","sourceRoot":"","sources":["../../../src/tests/integration/projectionContracts.integration.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prosopo/database",
3
- "version": "4.0.16",
3
+ "version": "4.0.18",
4
4
  "description": "Prosopo database plugins for provider",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -38,13 +38,13 @@
38
38
  "homepage": "https://github.com/prosopo/captcha#readme",
39
39
  "dependencies": {
40
40
  "@polkadot/util": "13.5.7",
41
- "@prosopo/common": "3.1.50",
42
- "@prosopo/logger": "2.0.6",
43
- "@prosopo/redis-client": "1.0.32",
44
- "@prosopo/types": "5.2.5",
45
- "@prosopo/types-database": "5.1.9",
46
- "@prosopo/user-access-policy": "3.12.24",
47
- "@prosopo/util": "3.3.6",
41
+ "@prosopo/common": "3.1.51",
42
+ "@prosopo/logger": "2.0.7",
43
+ "@prosopo/redis-client": "1.0.33",
44
+ "@prosopo/types": "5.2.6",
45
+ "@prosopo/types-database": "5.1.11",
46
+ "@prosopo/user-access-policy": "3.12.25",
47
+ "@prosopo/util": "3.3.7",
48
48
  "bson": "6.10.4",
49
49
  "make-dir": "3.1.0",
50
50
  "mongodb": "6.20.0",
@@ -52,7 +52,7 @@
52
52
  "mongoose": "8.24.1"
53
53
  },
54
54
  "devDependencies": {
55
- "@prosopo/config": "3.3.11",
55
+ "@prosopo/config": "3.3.12",
56
56
  "@types/node": "22.10.2",
57
57
  "@vitest/coverage-v8": "4.1.10",
58
58
  "concurrently": "9.0.1",
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=randomSamplingPerformance.integration.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"randomSamplingPerformance.integration.test.d.ts","sourceRoot":"","sources":["../../../src/tests/integration/randomSamplingPerformance.integration.test.ts"],"names":[],"mappings":""}
@@ -1,248 +0,0 @@
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
@@ -1 +0,0 @@
1
- {"version":3,"file":"randomSamplingPerformance.integration.test.js","sourceRoot":"","sources":["../../../src/tests/integration/randomSamplingPerformance.integration.test.ts"],"names":[],"mappings":"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"}