@prosopo/database 2.1.1 → 2.1.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/package.json +5 -5
- package/dist/base/index.d.ts +0 -3
- package/dist/base/index.d.ts.map +0 -1
- package/dist/base/index.js +0 -3
- package/dist/base/index.js.map +0 -1
- package/dist/base/mongo.d.ts +0 -16
- package/dist/base/mongo.d.ts.map +0 -1
- package/dist/base/mongo.js +0 -89
- package/dist/base/mongo.js.map +0 -1
- package/dist/base/mongoMemory.d.ts +0 -11
- package/dist/base/mongoMemory.d.ts.map +0 -1
- package/dist/base/mongoMemory.js +0 -27
- package/dist/base/mongoMemory.js.map +0 -1
- package/dist/cjs/base/index.cjs +0 -6
- package/dist/cjs/base/mongo.cjs +0 -97
- package/dist/cjs/base/mongoMemory.cjs +0 -28
- package/dist/cjs/databases/captcha.cjs +0 -82
- package/dist/cjs/databases/client.cjs +0 -46
- package/dist/cjs/databases/index.cjs +0 -19
- package/dist/cjs/databases/provider.cjs +0 -949
- package/dist/cjs/index.cjs +0 -15
- package/dist/databases/captcha.d.ts +0 -16
- package/dist/databases/captcha.d.ts.map +0 -1
- package/dist/databases/captcha.js +0 -75
- package/dist/databases/captcha.js.map +0 -1
- package/dist/databases/client.d.ts +0 -12
- package/dist/databases/client.d.ts.map +0 -1
- package/dist/databases/client.js +0 -42
- package/dist/databases/client.js.map +0 -1
- package/dist/databases/index.d.ts +0 -16
- package/dist/databases/index.d.ts.map +0 -1
- package/dist/databases/index.js +0 -17
- package/dist/databases/index.js.map +0 -1
- package/dist/databases/provider.d.ts +0 -70
- package/dist/databases/provider.d.ts.map +0 -1
- package/dist/databases/provider.js +0 -792
- package/dist/databases/provider.js.map +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -1,792 +0,0 @@
|
|
|
1
|
-
import { isHex } from "@polkadot/util/is";
|
|
2
|
-
import { ProsopoDBError, ProsopoEnvError } from "@prosopo/common";
|
|
3
|
-
import { CaptchaStates, CaptchaStatus, DatasetWithIdsAndTreeSchema, } from "@prosopo/types";
|
|
4
|
-
import { CaptchaRecordSchema, ClientRecordSchema, DatasetRecordSchema, PendingRecordSchema, PoWCaptchaRecordSchema, ScheduledTaskRecordSchema, ScheduledTaskSchema, SolutionRecordSchema, StoredStatusNames, UserCommitmentRecordSchema, UserCommitmentSchema, UserSolutionRecordSchema, } from "@prosopo/types-database";
|
|
5
|
-
import { MongoDatabase } from "../base/mongo.js";
|
|
6
|
-
var TableNames;
|
|
7
|
-
(function (TableNames) {
|
|
8
|
-
TableNames["captcha"] = "captcha";
|
|
9
|
-
TableNames["dataset"] = "dataset";
|
|
10
|
-
TableNames["solution"] = "solution";
|
|
11
|
-
TableNames["commitment"] = "commitment";
|
|
12
|
-
TableNames["usersolution"] = "usersolution";
|
|
13
|
-
TableNames["pending"] = "pending";
|
|
14
|
-
TableNames["scheduler"] = "scheduler";
|
|
15
|
-
TableNames["powcaptcha"] = "powcaptcha";
|
|
16
|
-
TableNames["client"] = "client";
|
|
17
|
-
})(TableNames || (TableNames = {}));
|
|
18
|
-
const PROVIDER_TABLES = [
|
|
19
|
-
{
|
|
20
|
-
collectionName: TableNames.captcha,
|
|
21
|
-
modelName: "Captcha",
|
|
22
|
-
schema: CaptchaRecordSchema,
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
collectionName: TableNames.powcaptcha,
|
|
26
|
-
modelName: "PowCaptcha",
|
|
27
|
-
schema: PoWCaptchaRecordSchema,
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
collectionName: TableNames.dataset,
|
|
31
|
-
modelName: "Dataset",
|
|
32
|
-
schema: DatasetRecordSchema,
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
collectionName: TableNames.solution,
|
|
36
|
-
modelName: "Solution",
|
|
37
|
-
schema: SolutionRecordSchema,
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
collectionName: TableNames.commitment,
|
|
41
|
-
modelName: "UserCommitment",
|
|
42
|
-
schema: UserCommitmentRecordSchema,
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
collectionName: TableNames.usersolution,
|
|
46
|
-
modelName: "UserSolution",
|
|
47
|
-
schema: UserSolutionRecordSchema,
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
collectionName: TableNames.pending,
|
|
51
|
-
modelName: "Pending",
|
|
52
|
-
schema: PendingRecordSchema,
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
collectionName: TableNames.scheduler,
|
|
56
|
-
modelName: "Scheduler",
|
|
57
|
-
schema: ScheduledTaskRecordSchema,
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
collectionName: TableNames.client,
|
|
61
|
-
modelName: "Client",
|
|
62
|
-
schema: ClientRecordSchema,
|
|
63
|
-
},
|
|
64
|
-
];
|
|
65
|
-
export class ProviderDatabase extends MongoDatabase {
|
|
66
|
-
constructor(url, dbname, authSource, logger) {
|
|
67
|
-
super(url, dbname, authSource, logger);
|
|
68
|
-
this.tables = {};
|
|
69
|
-
this.tables = {};
|
|
70
|
-
}
|
|
71
|
-
async connect() {
|
|
72
|
-
await super.connect();
|
|
73
|
-
this.loadTables();
|
|
74
|
-
}
|
|
75
|
-
loadTables() {
|
|
76
|
-
const tables = {};
|
|
77
|
-
PROVIDER_TABLES.map(({ collectionName, modelName, schema }) => {
|
|
78
|
-
if (this.connection) {
|
|
79
|
-
tables[collectionName] = this.connection.model(modelName, schema);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
this.tables = tables;
|
|
83
|
-
}
|
|
84
|
-
getTables() {
|
|
85
|
-
if (!this.tables) {
|
|
86
|
-
throw new ProsopoDBError("DATABASE.TABLES_UNDEFINED", {
|
|
87
|
-
context: { failedFuncName: this.getTables.name },
|
|
88
|
-
logger: this.logger,
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
return this.tables;
|
|
92
|
-
}
|
|
93
|
-
async storeDataset(dataset) {
|
|
94
|
-
try {
|
|
95
|
-
this.logger.debug("Storing dataset in database");
|
|
96
|
-
const parsedDataset = DatasetWithIdsAndTreeSchema.parse(dataset);
|
|
97
|
-
const datasetDoc = {
|
|
98
|
-
datasetId: parsedDataset.datasetId,
|
|
99
|
-
datasetContentId: parsedDataset.datasetContentId,
|
|
100
|
-
format: parsedDataset.format,
|
|
101
|
-
contentTree: parsedDataset.contentTree,
|
|
102
|
-
solutionTree: parsedDataset.solutionTree,
|
|
103
|
-
};
|
|
104
|
-
await this.tables.dataset?.updateOne({ datasetId: parsedDataset.datasetId }, { $set: datasetDoc }, { upsert: true });
|
|
105
|
-
const captchaDocs = parsedDataset.captchas.map(({ solution, ...captcha }, index) => ({
|
|
106
|
-
...captcha,
|
|
107
|
-
datasetId: parsedDataset.datasetId,
|
|
108
|
-
datasetContentId: parsedDataset.datasetContentId,
|
|
109
|
-
index,
|
|
110
|
-
solved: !!solution?.length,
|
|
111
|
-
}));
|
|
112
|
-
this.logger.debug("Inserting captcha records");
|
|
113
|
-
if (captchaDocs.length) {
|
|
114
|
-
await this.tables?.captcha.bulkWrite(captchaDocs.map((captchaDoc) => ({
|
|
115
|
-
updateOne: {
|
|
116
|
-
filter: { captchaId: captchaDoc.captchaId },
|
|
117
|
-
update: { $set: captchaDoc },
|
|
118
|
-
upsert: true,
|
|
119
|
-
},
|
|
120
|
-
})));
|
|
121
|
-
}
|
|
122
|
-
const captchaSolutionDocs = parsedDataset.captchas
|
|
123
|
-
.filter(({ solution }) => solution?.length)
|
|
124
|
-
.map((captcha) => ({
|
|
125
|
-
captchaId: captcha.captchaId,
|
|
126
|
-
captchaContentId: captcha.captchaContentId,
|
|
127
|
-
solution: captcha.solution,
|
|
128
|
-
salt: captcha.salt,
|
|
129
|
-
datasetId: parsedDataset.datasetId,
|
|
130
|
-
datasetContentId: parsedDataset.datasetContentId,
|
|
131
|
-
}));
|
|
132
|
-
this.logger.debug("Inserting solution records");
|
|
133
|
-
if (captchaSolutionDocs.length) {
|
|
134
|
-
await this.tables?.solution.bulkWrite(captchaSolutionDocs.map((captchaSolutionDoc) => ({
|
|
135
|
-
updateOne: {
|
|
136
|
-
filter: { captchaId: captchaSolutionDoc.captchaId },
|
|
137
|
-
update: { $set: captchaSolutionDoc },
|
|
138
|
-
upsert: true,
|
|
139
|
-
},
|
|
140
|
-
})));
|
|
141
|
-
}
|
|
142
|
-
this.logger.debug("Dataset stored in database");
|
|
143
|
-
}
|
|
144
|
-
catch (err) {
|
|
145
|
-
throw new ProsopoDBError("DATABASE.DATASET_LOAD_FAILED", {
|
|
146
|
-
context: { failedFuncName: this.storeDataset.name, error: err },
|
|
147
|
-
logger: this.logger,
|
|
148
|
-
});
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
async getSolutions(datasetId) {
|
|
152
|
-
const docs = await this.tables?.solution
|
|
153
|
-
.find({ datasetId })
|
|
154
|
-
.lean();
|
|
155
|
-
return docs ? docs : [];
|
|
156
|
-
}
|
|
157
|
-
async getDataset(datasetId) {
|
|
158
|
-
const datasetDoc = await this.tables?.dataset
|
|
159
|
-
.findOne({ datasetId: datasetId })
|
|
160
|
-
.lean();
|
|
161
|
-
if (datasetDoc) {
|
|
162
|
-
const { datasetContentId, format, contentTree, solutionTree } = datasetDoc;
|
|
163
|
-
const captchas = (await this.tables?.captcha.find({ datasetId }).lean()) ||
|
|
164
|
-
[];
|
|
165
|
-
const solutions = (await this.tables?.solution
|
|
166
|
-
.find({ datasetId })
|
|
167
|
-
.lean()) || [];
|
|
168
|
-
const solutionsKeyed = {};
|
|
169
|
-
for (const solution of solutions) {
|
|
170
|
-
solutionsKeyed[solution.captchaId] = solution;
|
|
171
|
-
}
|
|
172
|
-
return {
|
|
173
|
-
datasetId,
|
|
174
|
-
datasetContentId,
|
|
175
|
-
format,
|
|
176
|
-
contentTree: contentTree || [],
|
|
177
|
-
solutionTree: solutionTree || [],
|
|
178
|
-
captchas: captchas.map((captchaDoc) => {
|
|
179
|
-
const { captchaId, captchaContentId, items, target, salt, solved } = captchaDoc;
|
|
180
|
-
const solution = solutionsKeyed[captchaId];
|
|
181
|
-
return {
|
|
182
|
-
captchaId,
|
|
183
|
-
captchaContentId,
|
|
184
|
-
solved: !!solved,
|
|
185
|
-
salt,
|
|
186
|
-
items,
|
|
187
|
-
target,
|
|
188
|
-
solution: solved && solution ? solution.solution : [],
|
|
189
|
-
};
|
|
190
|
-
}),
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
throw new ProsopoDBError("DATABASE.DATASET_GET_FAILED", {
|
|
194
|
-
context: { failedFuncName: this.getDataset.name, datasetId },
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
async getRandomCaptcha(solved, datasetId, size) {
|
|
198
|
-
if (!isHex(datasetId)) {
|
|
199
|
-
throw new ProsopoDBError("DATABASE.INVALID_HASH", {
|
|
200
|
-
context: { failedFuncName: this.getRandomCaptcha.name, datasetId },
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
const sampleSize = size ? Math.abs(Math.trunc(size)) : 1;
|
|
204
|
-
const cursor = this.tables?.captcha.aggregate([
|
|
205
|
-
{ $match: { datasetId, solved } },
|
|
206
|
-
{ $sample: { size: sampleSize } },
|
|
207
|
-
{
|
|
208
|
-
$project: {
|
|
209
|
-
datasetId: 1,
|
|
210
|
-
datasetContentId: 1,
|
|
211
|
-
captchaId: 1,
|
|
212
|
-
captchaContentId: 1,
|
|
213
|
-
items: 1,
|
|
214
|
-
target: 1,
|
|
215
|
-
},
|
|
216
|
-
},
|
|
217
|
-
]);
|
|
218
|
-
const docs = await cursor;
|
|
219
|
-
if (docs?.length) {
|
|
220
|
-
return docs.map(({ _id, ...keepAttrs }) => keepAttrs);
|
|
221
|
-
}
|
|
222
|
-
throw new ProsopoDBError("DATABASE.CAPTCHA_GET_FAILED", {
|
|
223
|
-
context: {
|
|
224
|
-
failedFuncName: this.getRandomCaptcha.name,
|
|
225
|
-
solved,
|
|
226
|
-
datasetId,
|
|
227
|
-
size,
|
|
228
|
-
},
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
async getCaptchaById(captchaId) {
|
|
232
|
-
const cursor = this.tables?.captcha
|
|
233
|
-
.find({ captchaId: { $in: captchaId } })
|
|
234
|
-
.lean();
|
|
235
|
-
const docs = await cursor;
|
|
236
|
-
if (docs?.length) {
|
|
237
|
-
return docs.map(({ _id, ...keepAttrs }) => keepAttrs);
|
|
238
|
-
}
|
|
239
|
-
throw new ProsopoDBError("DATABASE.CAPTCHA_GET_FAILED", {
|
|
240
|
-
context: { failedFuncName: this.getCaptchaById.name, captchaId },
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
async updateCaptcha(captcha, datasetId) {
|
|
244
|
-
if (!isHex(datasetId)) {
|
|
245
|
-
throw new ProsopoDBError("DATABASE.INVALID_HASH", {
|
|
246
|
-
context: { failedFuncName: this.updateCaptcha.name, datasetId },
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
try {
|
|
250
|
-
await this.tables?.captcha.updateOne({ datasetId }, { $set: captcha }, { upsert: false });
|
|
251
|
-
}
|
|
252
|
-
catch (err) {
|
|
253
|
-
throw new ProsopoDBError("DATABASE.CAPTCHA_UPDATE_FAILED", {
|
|
254
|
-
context: { failedFuncName: this.getDatasetDetails.name, error: err },
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
async removeCaptchas(captchaIds) {
|
|
259
|
-
await this.tables?.captcha.deleteMany({ captchaId: { $in: captchaIds } });
|
|
260
|
-
}
|
|
261
|
-
async getDatasetDetails(datasetId) {
|
|
262
|
-
if (!isHex(datasetId)) {
|
|
263
|
-
throw new ProsopoDBError("DATABASE.INVALID_HASH", {
|
|
264
|
-
context: { failedFuncName: this.getDatasetDetails.name, datasetId },
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
const doc = await this.tables?.dataset
|
|
268
|
-
.findOne({ datasetId })
|
|
269
|
-
.lean();
|
|
270
|
-
if (doc) {
|
|
271
|
-
return doc;
|
|
272
|
-
}
|
|
273
|
-
throw new ProsopoDBError("DATABASE.DATASET_GET_FAILED", {
|
|
274
|
-
context: {
|
|
275
|
-
failedFuncName: this.getDatasetDetails.name,
|
|
276
|
-
datasetId,
|
|
277
|
-
},
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
async storeDappUserSolution(captchas, commit) {
|
|
281
|
-
const commitmentRecord = UserCommitmentSchema.parse({
|
|
282
|
-
...commit,
|
|
283
|
-
lastUpdatedTimestamp: Date.now(),
|
|
284
|
-
});
|
|
285
|
-
if (captchas.length) {
|
|
286
|
-
await this.tables?.commitment.updateOne({
|
|
287
|
-
id: commit.id,
|
|
288
|
-
}, commitmentRecord, { upsert: true });
|
|
289
|
-
const ops = captchas.map((captcha) => ({
|
|
290
|
-
updateOne: {
|
|
291
|
-
filter: { commitmentId: commit.id, captchaId: captcha.captchaId },
|
|
292
|
-
update: {
|
|
293
|
-
$set: {
|
|
294
|
-
captchaId: captcha.captchaId,
|
|
295
|
-
captchaContentId: captcha.captchaContentId,
|
|
296
|
-
salt: captcha.salt,
|
|
297
|
-
solution: captcha.solution,
|
|
298
|
-
commitmentId: commit.id,
|
|
299
|
-
processed: false,
|
|
300
|
-
},
|
|
301
|
-
},
|
|
302
|
-
upsert: true,
|
|
303
|
-
},
|
|
304
|
-
}));
|
|
305
|
-
await this.tables?.usersolution.bulkWrite(ops);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
async storePowCaptchaRecord(challenge, components, difficulty, providerSignature, ipAddress, headers, serverChecked = false, userSubmitted = false, storedStatus = StoredStatusNames.notStored, userSignature) {
|
|
309
|
-
const tables = this.getTables();
|
|
310
|
-
const powCaptchaRecord = {
|
|
311
|
-
challenge,
|
|
312
|
-
...components,
|
|
313
|
-
ipAddress,
|
|
314
|
-
headers,
|
|
315
|
-
result: { status: CaptchaStatus.pending },
|
|
316
|
-
userSubmitted,
|
|
317
|
-
serverChecked,
|
|
318
|
-
difficulty,
|
|
319
|
-
providerSignature,
|
|
320
|
-
userSignature,
|
|
321
|
-
lastUpdatedTimestamp: Date.now(),
|
|
322
|
-
};
|
|
323
|
-
try {
|
|
324
|
-
await tables.powcaptcha.create(powCaptchaRecord);
|
|
325
|
-
this.logger.info("PowCaptcha record added successfully", {
|
|
326
|
-
challenge,
|
|
327
|
-
userSubmitted,
|
|
328
|
-
serverChecked,
|
|
329
|
-
storedStatus,
|
|
330
|
-
});
|
|
331
|
-
}
|
|
332
|
-
catch (error) {
|
|
333
|
-
this.logger.error("Failed to add PowCaptcha record", {
|
|
334
|
-
error,
|
|
335
|
-
challenge,
|
|
336
|
-
userSubmitted,
|
|
337
|
-
serverChecked,
|
|
338
|
-
storedStatus,
|
|
339
|
-
});
|
|
340
|
-
throw new ProsopoDBError("DATABASE.CAPTCHA_UPDATE_FAILED", {
|
|
341
|
-
context: {
|
|
342
|
-
error,
|
|
343
|
-
challenge,
|
|
344
|
-
userSubmitted,
|
|
345
|
-
serverChecked,
|
|
346
|
-
storedStatus,
|
|
347
|
-
},
|
|
348
|
-
logger: this.logger,
|
|
349
|
-
});
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
async getPowCaptchaRecordByChallenge(challenge) {
|
|
353
|
-
if (!this.tables) {
|
|
354
|
-
throw new ProsopoEnvError("DATABASE.DATABASE_UNDEFINED", {
|
|
355
|
-
context: { failedFuncName: this.getPowCaptchaRecordByChallenge.name },
|
|
356
|
-
logger: this.logger,
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
try {
|
|
360
|
-
const record = await this.tables.powcaptcha
|
|
361
|
-
.findOne({ challenge })
|
|
362
|
-
.lean();
|
|
363
|
-
if (record) {
|
|
364
|
-
this.logger.info("PowCaptcha record retrieved successfully", {
|
|
365
|
-
challenge,
|
|
366
|
-
});
|
|
367
|
-
return record;
|
|
368
|
-
}
|
|
369
|
-
this.logger.info("No PowCaptcha record found", { challenge });
|
|
370
|
-
return null;
|
|
371
|
-
}
|
|
372
|
-
catch (error) {
|
|
373
|
-
this.logger.error("Failed to retrieve PowCaptcha record", {
|
|
374
|
-
error,
|
|
375
|
-
challenge,
|
|
376
|
-
});
|
|
377
|
-
throw new ProsopoDBError("DATABASE.CAPTCHA_GET_FAILED", {
|
|
378
|
-
context: { error, challenge },
|
|
379
|
-
logger: this.logger,
|
|
380
|
-
});
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
async updatePowCaptchaRecord(challenge, result, serverChecked = false, userSubmitted = false, userSignature) {
|
|
384
|
-
const tables = this.getTables();
|
|
385
|
-
const timestamp = Date.now();
|
|
386
|
-
const update = {
|
|
387
|
-
result,
|
|
388
|
-
serverChecked,
|
|
389
|
-
userSubmitted,
|
|
390
|
-
userSignature,
|
|
391
|
-
lastUpdatedTimestamp: timestamp,
|
|
392
|
-
};
|
|
393
|
-
try {
|
|
394
|
-
const updateResult = await tables.powcaptcha.updateOne({ challenge }, {
|
|
395
|
-
$set: update,
|
|
396
|
-
});
|
|
397
|
-
if (updateResult.matchedCount === 0) {
|
|
398
|
-
this.logger.info("No PowCaptcha record found to update", {
|
|
399
|
-
challenge,
|
|
400
|
-
...update,
|
|
401
|
-
});
|
|
402
|
-
throw new ProsopoDBError("DATABASE.CAPTCHA_GET_FAILED", {
|
|
403
|
-
context: {
|
|
404
|
-
challenge,
|
|
405
|
-
...update,
|
|
406
|
-
},
|
|
407
|
-
logger: this.logger,
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
this.logger.info("PowCaptcha record updated successfully", {
|
|
411
|
-
challenge,
|
|
412
|
-
...update,
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
catch (error) {
|
|
416
|
-
this.logger.error("Failed to update PowCaptcha record", {
|
|
417
|
-
error,
|
|
418
|
-
challenge,
|
|
419
|
-
...update,
|
|
420
|
-
});
|
|
421
|
-
throw new ProsopoDBError("DATABASE.CAPTCHA_UPDATE_FAILED", {
|
|
422
|
-
context: {
|
|
423
|
-
error,
|
|
424
|
-
challenge,
|
|
425
|
-
...update,
|
|
426
|
-
},
|
|
427
|
-
logger: this.logger,
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
async getProcessedDappUserSolutions() {
|
|
432
|
-
const docs = await this.tables?.usersolution
|
|
433
|
-
.find({ processed: true })
|
|
434
|
-
.lean();
|
|
435
|
-
return docs || [];
|
|
436
|
-
}
|
|
437
|
-
async getProcessedDappUserCommitments() {
|
|
438
|
-
const docs = await this.tables?.commitment
|
|
439
|
-
.find({ processed: true })
|
|
440
|
-
.lean();
|
|
441
|
-
return docs || [];
|
|
442
|
-
}
|
|
443
|
-
async getCheckedDappUserCommitments() {
|
|
444
|
-
const docs = await this.tables?.commitment
|
|
445
|
-
.find({ [StoredStatusNames.serverChecked]: true })
|
|
446
|
-
.lean();
|
|
447
|
-
return docs || [];
|
|
448
|
-
}
|
|
449
|
-
async getUnstoredDappUserCommitments() {
|
|
450
|
-
const docs = await this.tables?.commitment
|
|
451
|
-
.find({
|
|
452
|
-
$or: [
|
|
453
|
-
{ storedStatus: { $ne: StoredStatusNames.stored } },
|
|
454
|
-
{ storedStatus: { $exists: false } },
|
|
455
|
-
],
|
|
456
|
-
})
|
|
457
|
-
.lean();
|
|
458
|
-
return docs || [];
|
|
459
|
-
}
|
|
460
|
-
async markDappUserCommitmentsStored(commitmentIds) {
|
|
461
|
-
const updateDoc = {
|
|
462
|
-
storedAtTimestamp: Date.now(),
|
|
463
|
-
};
|
|
464
|
-
await this.tables?.commitment.updateMany({ id: { $in: commitmentIds } }, { $set: updateDoc }, { upsert: false });
|
|
465
|
-
}
|
|
466
|
-
async markDappUserCommitmentsChecked(commitmentIds) {
|
|
467
|
-
const updateDoc = {
|
|
468
|
-
[StoredStatusNames.serverChecked]: true,
|
|
469
|
-
lastUpdatedTimestamp: Date.now(),
|
|
470
|
-
};
|
|
471
|
-
await this.tables?.commitment.updateMany({ id: { $in: commitmentIds } }, { $set: updateDoc }, { upsert: false });
|
|
472
|
-
}
|
|
473
|
-
async getUnstoredDappUserPoWCommitments() {
|
|
474
|
-
const docs = await this.tables?.powcaptcha
|
|
475
|
-
.find({
|
|
476
|
-
$or: [
|
|
477
|
-
{ storedStatus: { $ne: StoredStatusNames.stored } },
|
|
478
|
-
{ storedStatus: { $exists: false } },
|
|
479
|
-
],
|
|
480
|
-
})
|
|
481
|
-
.lean();
|
|
482
|
-
return docs || [];
|
|
483
|
-
}
|
|
484
|
-
async markDappUserPoWCommitmentsStored(challenges) {
|
|
485
|
-
const updateDoc = {
|
|
486
|
-
storedAtTimestamp: Date.now(),
|
|
487
|
-
};
|
|
488
|
-
await this.tables?.powcaptcha.updateMany({ challenge: { $in: challenges } }, { $set: updateDoc }, { upsert: false });
|
|
489
|
-
}
|
|
490
|
-
async markDappUserPoWCommitmentsChecked(challenges) {
|
|
491
|
-
const updateDoc = {
|
|
492
|
-
[StoredStatusNames.serverChecked]: true,
|
|
493
|
-
lastUpdatedTimestamp: Date.now(),
|
|
494
|
-
};
|
|
495
|
-
await this.tables?.powcaptcha.updateMany({ challenge: { $in: challenges } }, {
|
|
496
|
-
$set: updateDoc,
|
|
497
|
-
}, { upsert: false });
|
|
498
|
-
}
|
|
499
|
-
async removeProcessedDappUserSolutions(commitmentIds) {
|
|
500
|
-
return this.tables?.usersolution.deleteMany({
|
|
501
|
-
processed: true,
|
|
502
|
-
commitmentId: { $in: commitmentIds },
|
|
503
|
-
});
|
|
504
|
-
}
|
|
505
|
-
async removeProcessedDappUserCommitments(commitmentIds) {
|
|
506
|
-
return this.tables?.commitment.deleteMany({
|
|
507
|
-
processed: true,
|
|
508
|
-
id: { $in: commitmentIds },
|
|
509
|
-
});
|
|
510
|
-
}
|
|
511
|
-
async storeDappUserPending(userAccount, requestHash, salt, deadlineTimestamp, requestedAtTimestamp, ipAddress) {
|
|
512
|
-
if (!isHex(requestHash)) {
|
|
513
|
-
throw new ProsopoDBError("DATABASE.INVALID_HASH", {
|
|
514
|
-
context: {
|
|
515
|
-
failedFuncName: this.storeDappUserPending.name,
|
|
516
|
-
requestHash,
|
|
517
|
-
},
|
|
518
|
-
});
|
|
519
|
-
}
|
|
520
|
-
const pendingRecord = {
|
|
521
|
-
accountId: userAccount,
|
|
522
|
-
pending: true,
|
|
523
|
-
salt,
|
|
524
|
-
requestHash,
|
|
525
|
-
deadlineTimestamp,
|
|
526
|
-
requestedAtTimestamp,
|
|
527
|
-
ipAddress,
|
|
528
|
-
};
|
|
529
|
-
await this.tables?.pending.updateOne({ requestHash: requestHash }, { $set: pendingRecord }, { upsert: true });
|
|
530
|
-
}
|
|
531
|
-
async getDappUserPending(requestHash) {
|
|
532
|
-
if (!isHex(requestHash)) {
|
|
533
|
-
throw new ProsopoEnvError("DATABASE.INVALID_HASH", {
|
|
534
|
-
context: { failedFuncName: this.getDappUserPending.name, requestHash },
|
|
535
|
-
});
|
|
536
|
-
}
|
|
537
|
-
const doc = await this.tables?.pending
|
|
538
|
-
.findOne({ requestHash: requestHash })
|
|
539
|
-
.lean();
|
|
540
|
-
if (doc) {
|
|
541
|
-
return doc;
|
|
542
|
-
}
|
|
543
|
-
throw new ProsopoEnvError("DATABASE.PENDING_RECORD_NOT_FOUND", {
|
|
544
|
-
context: { failedFuncName: this.getDappUserPending.name, requestHash },
|
|
545
|
-
});
|
|
546
|
-
}
|
|
547
|
-
async updateDappUserPendingStatus(requestHash) {
|
|
548
|
-
if (!isHex(requestHash)) {
|
|
549
|
-
throw new ProsopoEnvError("DATABASE.INVALID_HASH", {
|
|
550
|
-
context: {
|
|
551
|
-
failedFuncName: this.updateDappUserPendingStatus.name,
|
|
552
|
-
requestHash,
|
|
553
|
-
},
|
|
554
|
-
});
|
|
555
|
-
}
|
|
556
|
-
await this.tables?.pending.updateOne({ requestHash: requestHash }, {
|
|
557
|
-
$set: {
|
|
558
|
-
[CaptchaStatus.pending]: false,
|
|
559
|
-
},
|
|
560
|
-
}, { upsert: true });
|
|
561
|
-
}
|
|
562
|
-
async getAllCaptchasByDatasetId(datasetId, state) {
|
|
563
|
-
const cursor = this.tables?.captcha
|
|
564
|
-
.find({
|
|
565
|
-
datasetId,
|
|
566
|
-
solved: state === CaptchaStates.Solved,
|
|
567
|
-
})
|
|
568
|
-
.lean();
|
|
569
|
-
const docs = await cursor;
|
|
570
|
-
if (docs) {
|
|
571
|
-
return docs.map(({ _id, ...keepAttrs }) => keepAttrs);
|
|
572
|
-
}
|
|
573
|
-
throw new ProsopoEnvError("DATABASE.CAPTCHA_GET_FAILED");
|
|
574
|
-
}
|
|
575
|
-
async getAllDappUserSolutions(captchaId) {
|
|
576
|
-
const cursor = this.tables?.usersolution
|
|
577
|
-
?.find({ captchaId: { $in: captchaId } })
|
|
578
|
-
.lean();
|
|
579
|
-
const docs = await cursor;
|
|
580
|
-
if (docs) {
|
|
581
|
-
return docs.map(({ _id, ...keepAttrs }) => keepAttrs);
|
|
582
|
-
}
|
|
583
|
-
throw new ProsopoEnvError("DATABASE.SOLUTION_GET_FAILED");
|
|
584
|
-
}
|
|
585
|
-
async getDatasetIdWithSolvedCaptchasOfSizeN(solvedCaptchaCount) {
|
|
586
|
-
const cursor = this.tables?.solution.aggregate([
|
|
587
|
-
{
|
|
588
|
-
$match: {},
|
|
589
|
-
},
|
|
590
|
-
{
|
|
591
|
-
$group: {
|
|
592
|
-
_id: "$datasetId",
|
|
593
|
-
count: { $sum: 1 },
|
|
594
|
-
},
|
|
595
|
-
},
|
|
596
|
-
{
|
|
597
|
-
$match: {
|
|
598
|
-
count: { $gte: solvedCaptchaCount },
|
|
599
|
-
},
|
|
600
|
-
},
|
|
601
|
-
{
|
|
602
|
-
$sample: { size: 1 },
|
|
603
|
-
},
|
|
604
|
-
]);
|
|
605
|
-
const docs = await cursor;
|
|
606
|
-
if (docs?.length) {
|
|
607
|
-
return docs[0]._id;
|
|
608
|
-
}
|
|
609
|
-
throw new ProsopoDBError("DATABASE.DATASET_WITH_SOLUTIONS_GET_FAILED");
|
|
610
|
-
}
|
|
611
|
-
async getRandomSolvedCaptchasFromSingleDataset(datasetId, size) {
|
|
612
|
-
if (!isHex(datasetId)) {
|
|
613
|
-
throw new ProsopoDBError("DATABASE.INVALID_HASH", {
|
|
614
|
-
context: {
|
|
615
|
-
failedFuncName: this.getRandomSolvedCaptchasFromSingleDataset.name,
|
|
616
|
-
datasetId,
|
|
617
|
-
},
|
|
618
|
-
});
|
|
619
|
-
}
|
|
620
|
-
const sampleSize = size ? Math.abs(Math.trunc(size)) : 1;
|
|
621
|
-
const cursor = this.tables?.solution.aggregate([
|
|
622
|
-
{ $match: { datasetId } },
|
|
623
|
-
{ $sample: { size: sampleSize } },
|
|
624
|
-
{
|
|
625
|
-
$project: {
|
|
626
|
-
captchaId: 1,
|
|
627
|
-
captchaContentId: 1,
|
|
628
|
-
solution: 1,
|
|
629
|
-
},
|
|
630
|
-
},
|
|
631
|
-
]);
|
|
632
|
-
const docs = await cursor;
|
|
633
|
-
if (docs?.length) {
|
|
634
|
-
return docs;
|
|
635
|
-
}
|
|
636
|
-
throw new ProsopoDBError("DATABASE.SOLUTION_GET_FAILED", {
|
|
637
|
-
context: {
|
|
638
|
-
failedFuncName: this.getRandomSolvedCaptchasFromSingleDataset.name,
|
|
639
|
-
datasetId,
|
|
640
|
-
size,
|
|
641
|
-
},
|
|
642
|
-
});
|
|
643
|
-
}
|
|
644
|
-
async getDappUserSolutionById(commitmentId) {
|
|
645
|
-
const cursor = this.tables?.usersolution
|
|
646
|
-
?.findOne({
|
|
647
|
-
commitmentId: commitmentId,
|
|
648
|
-
}, { projection: { _id: 0 } })
|
|
649
|
-
.lean();
|
|
650
|
-
const doc = await cursor;
|
|
651
|
-
if (doc) {
|
|
652
|
-
return doc;
|
|
653
|
-
}
|
|
654
|
-
throw new ProsopoDBError("DATABASE.SOLUTION_GET_FAILED", {
|
|
655
|
-
context: { failedFuncName: this.getCaptchaById.name, commitmentId },
|
|
656
|
-
});
|
|
657
|
-
}
|
|
658
|
-
async getDappUserCommitmentById(commitmentId) {
|
|
659
|
-
const commitmentCursor = this.tables?.commitment
|
|
660
|
-
?.findOne({ id: commitmentId })
|
|
661
|
-
.lean();
|
|
662
|
-
const doc = await commitmentCursor;
|
|
663
|
-
return doc ? doc : undefined;
|
|
664
|
-
}
|
|
665
|
-
async getDappUserCommitmentByAccount(userAccount, dappAccount) {
|
|
666
|
-
const docs = await this.tables?.commitment
|
|
667
|
-
?.find({ userAccount, dappAccount }, { _id: 0 }, { sort: { _id: -1 } })
|
|
668
|
-
.lean();
|
|
669
|
-
return docs ? docs : [];
|
|
670
|
-
}
|
|
671
|
-
async approveDappUserCommitment(commitmentId) {
|
|
672
|
-
try {
|
|
673
|
-
const result = { status: CaptchaStatus.approved };
|
|
674
|
-
const updateDoc = {
|
|
675
|
-
result,
|
|
676
|
-
lastUpdatedTimestamp: Date.now(),
|
|
677
|
-
};
|
|
678
|
-
await this.tables?.commitment
|
|
679
|
-
?.findOneAndUpdate({ id: commitmentId }, { $set: updateDoc }, { upsert: false })
|
|
680
|
-
.lean();
|
|
681
|
-
}
|
|
682
|
-
catch (err) {
|
|
683
|
-
throw new ProsopoDBError("DATABASE.SOLUTION_APPROVE_FAILED", {
|
|
684
|
-
context: { error: err, commitmentId },
|
|
685
|
-
});
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
async disapproveDappUserCommitment(commitmentId, reason) {
|
|
689
|
-
try {
|
|
690
|
-
const updateDoc = {
|
|
691
|
-
result: { status: CaptchaStatus.disapproved, reason },
|
|
692
|
-
lastUpdatedTimestamp: Date.now(),
|
|
693
|
-
};
|
|
694
|
-
await this.tables?.commitment
|
|
695
|
-
?.findOneAndUpdate({ id: commitmentId }, { $set: updateDoc }, { upsert: false })
|
|
696
|
-
.lean();
|
|
697
|
-
}
|
|
698
|
-
catch (err) {
|
|
699
|
-
throw new ProsopoDBError("DATABASE.SOLUTION_APPROVE_FAILED", {
|
|
700
|
-
context: { error: err, commitmentId },
|
|
701
|
-
});
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
async flagProcessedDappUserSolutions(captchaIds) {
|
|
705
|
-
try {
|
|
706
|
-
await this.tables?.usersolution
|
|
707
|
-
?.updateMany({ captchaId: { $in: captchaIds } }, { $set: { processed: true } }, { upsert: false })
|
|
708
|
-
.lean();
|
|
709
|
-
}
|
|
710
|
-
catch (err) {
|
|
711
|
-
throw new ProsopoDBError("DATABASE.SOLUTION_FLAG_FAILED", {
|
|
712
|
-
context: { error: err, captchaIds },
|
|
713
|
-
});
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
async flagProcessedDappUserCommitments(commitmentIds) {
|
|
717
|
-
try {
|
|
718
|
-
const distinctCommitmentIds = [...new Set(commitmentIds)];
|
|
719
|
-
await this.tables?.commitment
|
|
720
|
-
?.updateMany({ id: { $in: distinctCommitmentIds } }, { $set: { processed: true } }, { upsert: false })
|
|
721
|
-
.lean();
|
|
722
|
-
}
|
|
723
|
-
catch (err) {
|
|
724
|
-
throw new ProsopoDBError("DATABASE.COMMITMENT_FLAG_FAILED", {
|
|
725
|
-
context: { error: err, commitmentIds },
|
|
726
|
-
});
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
async getScheduledTaskStatus(taskId, status) {
|
|
730
|
-
const cursor = await this.tables?.scheduler
|
|
731
|
-
?.findOne({ taskId: taskId, status: status })
|
|
732
|
-
.lean();
|
|
733
|
-
return cursor ? cursor : undefined;
|
|
734
|
-
}
|
|
735
|
-
async getLastScheduledTaskStatus(task, status) {
|
|
736
|
-
const lookup = { processName: task };
|
|
737
|
-
if (status) {
|
|
738
|
-
lookup.status = status;
|
|
739
|
-
}
|
|
740
|
-
const cursor = await this.tables?.scheduler
|
|
741
|
-
?.findOne(lookup)
|
|
742
|
-
.sort({ datetime: -1 })
|
|
743
|
-
.limit(1)
|
|
744
|
-
.lean();
|
|
745
|
-
return cursor ? cursor : undefined;
|
|
746
|
-
}
|
|
747
|
-
async createScheduledTaskStatus(taskName, status) {
|
|
748
|
-
const now = new Date().getTime();
|
|
749
|
-
const doc = ScheduledTaskSchema.parse({
|
|
750
|
-
processName: taskName,
|
|
751
|
-
datetime: now,
|
|
752
|
-
status,
|
|
753
|
-
});
|
|
754
|
-
const taskRecord = await this.tables?.scheduler.create(doc);
|
|
755
|
-
return taskRecord._id;
|
|
756
|
-
}
|
|
757
|
-
async updateScheduledTaskStatus(taskId, status, result) {
|
|
758
|
-
const update = {
|
|
759
|
-
status,
|
|
760
|
-
updated: new Date().getTime(),
|
|
761
|
-
...(result && { result }),
|
|
762
|
-
};
|
|
763
|
-
await this.tables?.scheduler.updateOne({ _id: taskId }, { $set: update }, {
|
|
764
|
-
upsert: false,
|
|
765
|
-
});
|
|
766
|
-
}
|
|
767
|
-
async updateClientRecords(clientRecords) {
|
|
768
|
-
const ops = clientRecords.map((record) => {
|
|
769
|
-
const clientRecord = {
|
|
770
|
-
account: record.account,
|
|
771
|
-
settings: record.settings,
|
|
772
|
-
};
|
|
773
|
-
return {
|
|
774
|
-
updateOne: {
|
|
775
|
-
filter: { account: record.account },
|
|
776
|
-
update: {
|
|
777
|
-
$set: clientRecord,
|
|
778
|
-
},
|
|
779
|
-
upsert: true,
|
|
780
|
-
},
|
|
781
|
-
};
|
|
782
|
-
});
|
|
783
|
-
await this.tables?.client.bulkWrite(ops);
|
|
784
|
-
}
|
|
785
|
-
async getClientRecord(account) {
|
|
786
|
-
const doc = await this.tables?.client
|
|
787
|
-
.findOne({ account })
|
|
788
|
-
.lean();
|
|
789
|
-
return doc ? doc : undefined;
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
//# sourceMappingURL=provider.js.map
|