@devtion/backend 0.0.0-004e6ad

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 (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +177 -0
  3. package/dist/src/functions/index.js +2884 -0
  4. package/dist/src/functions/index.mjs +2834 -0
  5. package/dist/types/functions/bandada.d.ts +4 -0
  6. package/dist/types/functions/bandada.d.ts.map +1 -0
  7. package/dist/types/functions/ceremony.d.ts +33 -0
  8. package/dist/types/functions/ceremony.d.ts.map +1 -0
  9. package/dist/types/functions/circuit.d.ts +63 -0
  10. package/dist/types/functions/circuit.d.ts.map +1 -0
  11. package/dist/types/functions/index.d.ts +9 -0
  12. package/dist/types/functions/index.d.ts.map +1 -0
  13. package/dist/types/functions/participant.d.ts +58 -0
  14. package/dist/types/functions/participant.d.ts.map +1 -0
  15. package/dist/types/functions/siwe.d.ts +4 -0
  16. package/dist/types/functions/siwe.d.ts.map +1 -0
  17. package/dist/types/functions/storage.d.ts +37 -0
  18. package/dist/types/functions/storage.d.ts.map +1 -0
  19. package/dist/types/functions/timeout.d.ts +26 -0
  20. package/dist/types/functions/timeout.d.ts.map +1 -0
  21. package/dist/types/functions/user.d.ts +15 -0
  22. package/dist/types/functions/user.d.ts.map +1 -0
  23. package/dist/types/lib/errors.d.ts +76 -0
  24. package/dist/types/lib/errors.d.ts.map +1 -0
  25. package/dist/types/lib/services.d.ts +16 -0
  26. package/dist/types/lib/services.d.ts.map +1 -0
  27. package/dist/types/lib/utils.d.ts +141 -0
  28. package/dist/types/lib/utils.d.ts.map +1 -0
  29. package/dist/types/types/enums.d.ts +13 -0
  30. package/dist/types/types/enums.d.ts.map +1 -0
  31. package/dist/types/types/index.d.ts +186 -0
  32. package/dist/types/types/index.d.ts.map +1 -0
  33. package/package.json +90 -0
  34. package/src/functions/bandada.ts +155 -0
  35. package/src/functions/ceremony.ts +338 -0
  36. package/src/functions/circuit.ts +1044 -0
  37. package/src/functions/index.ts +38 -0
  38. package/src/functions/participant.ts +526 -0
  39. package/src/functions/siwe.ts +77 -0
  40. package/src/functions/storage.ts +551 -0
  41. package/src/functions/timeout.ts +296 -0
  42. package/src/functions/user.ts +167 -0
  43. package/src/lib/errors.ts +242 -0
  44. package/src/lib/services.ts +64 -0
  45. package/src/lib/utils.ts +474 -0
  46. package/src/types/declarations.d.ts +1 -0
  47. package/src/types/enums.ts +12 -0
  48. package/src/types/index.ts +200 -0
  49. package/test/index.test.ts +62 -0
@@ -0,0 +1,474 @@
1
+ import {
2
+ DocumentData,
3
+ QuerySnapshot,
4
+ DocumentSnapshot,
5
+ QueryDocumentSnapshot,
6
+ Timestamp,
7
+ WhereFilterOp
8
+ } from "firebase-admin/firestore"
9
+ import admin from "firebase-admin"
10
+ import dotenv from "dotenv"
11
+ import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3"
12
+ import { getSignedUrl } from "@aws-sdk/s3-request-presigner"
13
+ import { createWriteStream } from "node:fs"
14
+ import { pipeline } from "node:stream"
15
+ import { promisify } from "node:util"
16
+ import { readFileSync } from "fs"
17
+ import mime from "mime-types"
18
+ import { encode } from "html-entities"
19
+ import { setTimeout } from "timers/promises"
20
+ import {
21
+ commonTerms,
22
+ getCircuitsCollectionPath,
23
+ getContributionsCollectionPath,
24
+ getTimeoutsCollectionPath,
25
+ CeremonyState,
26
+ finalContributionIndex,
27
+ CircuitDocument
28
+ } from "@devtion/actions"
29
+ import fetch from "@adobe/node-fetch-retry"
30
+ import path from "path"
31
+ import os from "os"
32
+ import { SSMClient } from "@aws-sdk/client-ssm"
33
+ import { EC2Client } from "@aws-sdk/client-ec2"
34
+ import { COMMON_ERRORS, logAndThrowError, SPECIFIC_ERRORS } from "./errors"
35
+ import { getS3Client } from "./services"
36
+
37
+ dotenv.config()
38
+
39
+ /**
40
+ * Get a specific document from database.
41
+ * @dev this method differs from the one in the `actions` package because we need to use
42
+ * the admin SDK here; therefore the Firestore instances are not interchangeable between admin
43
+ * and user instance.
44
+ * @param collection <string> - the name of the collection.
45
+ * @param documentId <string> - the unique identifier of the document in the collection.
46
+ * @returns <Promise<DocumentSnapshot<DocumentData>>> - the requested document w/ relative data.
47
+ */
48
+ export const getDocumentById = async (
49
+ collection: string,
50
+ documentId: string
51
+ ): Promise<DocumentSnapshot<DocumentData>> => {
52
+ // Prepare Firestore db instance.
53
+ const firestore = admin.firestore()
54
+
55
+ // Get document.
56
+ const doc = await firestore.collection(collection).doc(documentId).get()
57
+
58
+ // Return only if doc exists; otherwise throw error.
59
+ return doc.exists ? doc : logAndThrowError(COMMON_ERRORS.CM_INEXISTENT_DOCUMENT)
60
+ }
61
+
62
+ /**
63
+ * Get the current server timestamp.
64
+ * @dev the value is in milliseconds.
65
+ * @returns <number> - the timestamp of the server (ms).
66
+ */
67
+ export const getCurrentServerTimestampInMillis = (): number => Timestamp.now().toMillis()
68
+
69
+ /**
70
+ * Interrupt the current execution for a specified amount of time.
71
+ * @param ms <number> - the amount of time expressed in milliseconds.
72
+ */
73
+ export const sleep = async (ms: number): Promise<void> => setTimeout(ms)
74
+
75
+ /**
76
+ * Query for ceremony circuits.
77
+ * @notice the order by sequence position is fundamental to maintain parallelism among contributions for different circuits.
78
+ * @param ceremonyId <string> - the unique identifier of the ceremony.
79
+ * @returns Promise<Array<FirebaseDocumentInfo>> - the ceremony' circuits documents ordered by sequence position.
80
+ */
81
+ export const getCeremonyCircuits = async (ceremonyId: string): Promise<Array<QueryDocumentSnapshot<DocumentData>>> => {
82
+ // Prepare Firestore db instance.
83
+ const firestore = admin.firestore()
84
+
85
+ // Execute query.
86
+ const querySnap = await firestore.collection(getCircuitsCollectionPath(ceremonyId)).get()
87
+
88
+ if (!querySnap.docs) logAndThrowError(SPECIFIC_ERRORS.SE_CONTRIBUTE_NO_CEREMONY_CIRCUITS)
89
+
90
+ return querySnap.docs.sort(
91
+ (a: DocumentData, b: DocumentData) => a.data().sequencePosition - b.data().sequencePosition
92
+ )
93
+ }
94
+
95
+ /**
96
+ * Query for ceremony circuit contributions.
97
+ * @param ceremonyId <string> - the unique identifier of the ceremony.
98
+ * @param circuitId <string> - the unique identifier of the circuitId.
99
+ * @returns Promise<Array<FirebaseDocumentInfo>> - the contributions of the ceremony circuit.
100
+ */
101
+ export const getCeremonyCircuitContributions = async (
102
+ ceremonyId: string,
103
+ circuitId: string
104
+ ): Promise<Array<QueryDocumentSnapshot<DocumentData>>> => {
105
+ // Prepare Firestore db instance.
106
+ const firestore = admin.firestore()
107
+
108
+ // Execute query.
109
+ const querySnap = await firestore.collection(getContributionsCollectionPath(ceremonyId, circuitId)).get()
110
+
111
+ if (!querySnap.docs) logAndThrowError(SPECIFIC_ERRORS.SE_FINALIZE_NO_CEREMONY_CONTRIBUTIONS)
112
+
113
+ return querySnap.docs
114
+ }
115
+
116
+ /**
117
+ * Query not expired timeouts.
118
+ * @notice a timeout is considered valid (aka not expired) if and only if the timeout end date
119
+ * value is less than current timestamp.
120
+ * @param ceremonyId <string> - the unique identifier of the ceremony.
121
+ * @param participantId <string> - the unique identifier of the participant.
122
+ * @returns <Promise<QuerySnapshot<DocumentData>>>
123
+ */
124
+ export const queryNotExpiredTimeouts = async (
125
+ ceremonyId: string,
126
+ participantId: string
127
+ ): Promise<QuerySnapshot<DocumentData>> => {
128
+ // Prepare Firestore db.
129
+ const firestoreDb = admin.firestore()
130
+
131
+ // Execute and return query result.
132
+ return firestoreDb
133
+ .collection(getTimeoutsCollectionPath(ceremonyId, participantId))
134
+ .where(commonTerms.collections.timeouts.fields.endDate, ">=", getCurrentServerTimestampInMillis())
135
+ .get()
136
+ }
137
+
138
+ /**
139
+ * Query for opened ceremonies.
140
+ * @param firestoreDatabase <Firestore> - the Firestore service instance associated to the current Firebase application.
141
+ * @returns <Promise<Array<FirebaseDocumentInfo>>>
142
+ */
143
+ export const queryOpenedCeremonies = async (): Promise<Array<QueryDocumentSnapshot<DocumentData>>> => {
144
+ const querySnap = await admin
145
+ .firestore()
146
+ .collection(commonTerms.collections.ceremonies.name)
147
+ .where(commonTerms.collections.ceremonies.fields.state, "==", CeremonyState.OPENED)
148
+ .where(commonTerms.collections.ceremonies.fields.endDate, ">=", getCurrentServerTimestampInMillis())
149
+ .get()
150
+
151
+ if (!querySnap.docs) logAndThrowError(SPECIFIC_ERRORS.SE_CONTRIBUTE_NO_OPENED_CEREMONIES)
152
+
153
+ return querySnap.docs
154
+ }
155
+
156
+ /**
157
+ * Get ceremony circuit document by sequence position.
158
+ * @param ceremonyId <string> - the unique identifier of the ceremony.
159
+ * @param sequencePosition <number> - the sequence position of the circuit.
160
+ * @returns Promise<QueryDocumentSnapshot<DocumentData>>
161
+ */
162
+ export const getCircuitDocumentByPosition = async (
163
+ ceremonyId: string,
164
+ sequencePosition: number
165
+ ): Promise<QueryDocumentSnapshot<DocumentData>> => {
166
+ // Query for all ceremony circuits.
167
+ const circuits = await getCeremonyCircuits(ceremonyId)
168
+
169
+ // Apply a filter using the sequence position.
170
+ const matchedCircuits = circuits.filter(
171
+ (circuit: DocumentData) => circuit.data().sequencePosition === sequencePosition
172
+ )
173
+
174
+ if (matchedCircuits.length !== 1) logAndThrowError(COMMON_ERRORS.CM_NO_CIRCUIT_FOR_GIVEN_SEQUENCE_POSITION)
175
+
176
+ return matchedCircuits.at(0)!
177
+ }
178
+
179
+ /**
180
+ * Create a temporary file path in the virtual memory of the cloud function.
181
+ * @dev useful when downloading files from AWS S3 buckets for processing within cloud functions.
182
+ * @param completeFilename <string> - the complete file name (name + ext).
183
+ * @returns <string> - the path to the local temporary location.
184
+ */
185
+ export const createTemporaryLocalPath = (completeFilename: string): string => path.join(os.tmpdir(), completeFilename)
186
+
187
+ /**
188
+ * Download an artifact from the AWS S3 bucket.
189
+ * @dev this method uses streams.
190
+ * @param bucketName <string> - the name of the bucket.
191
+ * @param objectKey <string> - the unique key to identify the object inside the given AWS S3 bucket.
192
+ * @param localFilePath <string> - the local path where the file will be stored.
193
+ */
194
+ export const downloadArtifactFromS3Bucket = async (bucketName: string, objectKey: string, localFilePath: string) => {
195
+ // Prepare AWS S3 client instance.
196
+ const client = await getS3Client()
197
+
198
+ // Prepare command.
199
+ const command = new GetObjectCommand({ Bucket: bucketName, Key: objectKey })
200
+
201
+ // Generate a pre-signed url for downloading the file.
202
+ const url = await getSignedUrl(client, command, { expiresIn: Number(process.env.AWS_PRESIGNED_URL_EXPIRATION) })
203
+
204
+ // Execute download request.
205
+ // @ts-ignore
206
+ const response: any = await fetch(url, {
207
+ method: "GET",
208
+ headers: {
209
+ "Access-Control-Allow-Origin": "*"
210
+ }
211
+ })
212
+
213
+ if (response.status !== 200 || !response.ok) logAndThrowError(SPECIFIC_ERRORS.SE_STORAGE_DOWNLOAD_FAILED)
214
+
215
+ // Write the file locally using streams.
216
+ const writeStream = createWriteStream(localFilePath)
217
+ const streamPipeline = promisify(pipeline)
218
+ await streamPipeline(response.body, writeStream)
219
+
220
+ writeStream.on("finish", () => {
221
+ writeStream.end()
222
+ })
223
+ }
224
+
225
+ /**
226
+ * Upload a new artifact to the AWS S3 bucket.
227
+ * @dev this method uses streams.
228
+ * @param bucketName <string> - the name of the bucket.
229
+ * @param objectKey <string> - the unique key to identify the object inside the given AWS S3 bucket.
230
+ * @param localFilePath <string> - the local path where the file to be uploaded is stored.
231
+ */
232
+ export const uploadFileToBucket = async (
233
+ bucketName: string,
234
+ objectKey: string,
235
+ localFilePath: string,
236
+ isPublic: boolean = false
237
+ ) => {
238
+ // Prepare AWS S3 client instance.
239
+ const client = await getS3Client()
240
+
241
+ // Extract content type.
242
+ const contentType = mime.lookup(localFilePath) || ""
243
+
244
+ // Prepare command.
245
+ const command = new PutObjectCommand({
246
+ Bucket: bucketName,
247
+ Key: objectKey,
248
+ ContentType: contentType,
249
+ ACL: isPublic ? "public-read" : "private"
250
+ })
251
+
252
+ // Generate a pre-signed url for uploading the file.
253
+ const url = await getSignedUrl(client, command, { expiresIn: Number(process.env.AWS_PRESIGNED_URL_EXPIRATION) })
254
+
255
+ // Execute upload request.
256
+ // @ts-ignore
257
+ const response = await fetch(url, {
258
+ method: "PUT",
259
+ body: readFileSync(localFilePath),
260
+ headers: { "Content-Type": contentType }
261
+ })
262
+
263
+ if (response.status !== 200 || !response.ok) logAndThrowError(SPECIFIC_ERRORS.SE_STORAGE_UPLOAD_FAILED)
264
+ }
265
+
266
+ export const uploadFileToBucketNoFile = async (
267
+ bucketName: string,
268
+ objectKey: string,
269
+ data: string,
270
+ isPublic: boolean = false
271
+ ) => {
272
+ // Prepare AWS S3 client instance.
273
+ const client = await getS3Client()
274
+
275
+ // Prepare command.
276
+ const command = new PutObjectCommand({
277
+ Bucket: bucketName,
278
+ Key: objectKey,
279
+ ContentType: "text/plain",
280
+ ACL: isPublic ? "public-read" : "private"
281
+ })
282
+
283
+ // Generate a pre-signed url for uploading the file.
284
+ const url = await getSignedUrl(client, command, { expiresIn: Number(process.env.AWS_PRESIGNED_URL_EXPIRATION) })
285
+
286
+ // Execute upload request.
287
+ // @ts-ignore
288
+ const response = await fetch(url, {
289
+ method: "PUT",
290
+ body: data,
291
+ headers: { "Content-Type": "text/plain" }
292
+ })
293
+
294
+ if (response.status !== 200 || !response.ok) logAndThrowError(SPECIFIC_ERRORS.SE_STORAGE_UPLOAD_FAILED)
295
+ }
296
+
297
+ /**
298
+ * Upload an artifact from the AWS S3 bucket.
299
+ * @param bucketName <string> - the name of the bucket.
300
+ * @param objectKey <string> - the unique key to identify the object inside the given AWS S3 bucket.
301
+ */
302
+ export const deleteObject = async (bucketName: string, objectKey: string) => {
303
+ // Prepare AWS S3 client instance.
304
+ const client = await getS3Client()
305
+
306
+ // Prepare command.
307
+ const command = new DeleteObjectCommand({ Bucket: bucketName, Key: objectKey })
308
+
309
+ // Execute command.
310
+ const data = await client.send(command)
311
+
312
+ if (data.$metadata.httpStatusCode !== 204) logAndThrowError(SPECIFIC_ERRORS.SE_STORAGE_DELETE_FAILED)
313
+ }
314
+
315
+ /**
316
+ * Query ceremonies by state and (start/end) date value.
317
+ * @param state <string> - the state of the ceremony.
318
+ * @param needToCheckStartDate <boolean> - flag to discriminate when to check startDate (true) or endDate (false).
319
+ * @param check <WhereFilerOp> - the type of filter (query check - e.g., '<' or '>').
320
+ * @returns <Promise<admin.firestore.QuerySnapshot<admin.firestore.DocumentData>>> - the queried ceremonies after filtering operation.
321
+ */
322
+ export const queryCeremoniesByStateAndDate = async (
323
+ state: string,
324
+ needToCheckStartDate: boolean,
325
+ check: WhereFilterOp
326
+ ): Promise<admin.firestore.QuerySnapshot<admin.firestore.DocumentData>> =>
327
+ admin
328
+ .firestore()
329
+ .collection(commonTerms.collections.ceremonies.name)
330
+ .where(commonTerms.collections.ceremonies.fields.state, "==", state)
331
+ .where(
332
+ needToCheckStartDate
333
+ ? commonTerms.collections.ceremonies.fields.startDate
334
+ : commonTerms.collections.ceremonies.fields.endDate,
335
+ check,
336
+ getCurrentServerTimestampInMillis()
337
+ )
338
+ .get()
339
+
340
+ /**
341
+ * Return the document associated with the final contribution for a ceremony circuit.
342
+ * @dev this method is useful during ceremony finalization.
343
+ * @param ceremonyId <string> -
344
+ * @param circuitId <string> -
345
+ * @returns Promise<QueryDocumentSnapshot<DocumentData>> - the final contribution for the ceremony circuit.
346
+ */
347
+ export const getFinalContribution = async (
348
+ ceremonyId: string,
349
+ circuitId: string
350
+ ): Promise<QueryDocumentSnapshot<DocumentData>> => {
351
+ // Get contributions for the circuit.
352
+ const contributions = await getCeremonyCircuitContributions(ceremonyId, circuitId)
353
+
354
+ // Match the final one.
355
+ const matchContribution = contributions.filter(
356
+ (contribution: DocumentData) => contribution.data().zkeyIndex === finalContributionIndex
357
+ )
358
+
359
+ if (!matchContribution) logAndThrowError(SPECIFIC_ERRORS.SE_FINALIZE_NO_FINAL_CONTRIBUTION)
360
+
361
+ // Get the final contribution.
362
+ // nb. there must be only one final contributions x circuit.
363
+ const finalContribution = matchContribution.at(0)!
364
+
365
+ return finalContribution
366
+ }
367
+
368
+ /**
369
+ * Helper function to HTML encode circuit data.
370
+ * @param circuitDocument <CircuitDocument> - the circuit document to be encoded.
371
+ * @returns <CircuitDocument> - the circuit document encoded.
372
+ */
373
+ export const htmlEncodeCircuitData = (circuitDocument: CircuitDocument): CircuitDocument => ({
374
+ ...circuitDocument,
375
+ description: encode(circuitDocument.description),
376
+ name: encode(circuitDocument.name),
377
+ prefix: encode(circuitDocument.prefix)
378
+ })
379
+
380
+ /**
381
+ * Fetch the variables related to GitHub anti-sybil checks
382
+ * @returns <any> - the GitHub variables.
383
+ */
384
+ export const getGitHubVariables = (): any => {
385
+ if (
386
+ !process.env.GITHUB_MINIMUM_FOLLOWERS ||
387
+ !process.env.GITHUB_MINIMUM_FOLLOWING ||
388
+ !process.env.GITHUB_MINIMUM_PUBLIC_REPOS ||
389
+ !process.env.GITHUB_MINIMUM_AGE
390
+ )
391
+ logAndThrowError(COMMON_ERRORS.CM_WRONG_CONFIGURATION)
392
+
393
+ return {
394
+ minimumFollowers: Number(process.env.GITHUB_MINIMUM_FOLLOWERS),
395
+ minimumFollowing: Number(process.env.GITHUB_MINIMUM_FOLLOWING),
396
+ minimumPublicRepos: Number(process.env.GITHUB_MINIMUM_PUBLIC_REPOS),
397
+ minimumAge: Number(process.env.GITHUB_MINIMUM_AGE)
398
+ }
399
+ }
400
+
401
+ /**
402
+ * Fetch the variables related to EC2 verification
403
+ * @returns <any> - the AWS EC2 variables.
404
+ */
405
+ export const getAWSVariables = (): any => {
406
+ if (
407
+ !process.env.AWS_ACCESS_KEY_ID ||
408
+ !process.env.AWS_SECRET_ACCESS_KEY ||
409
+ !process.env.AWS_INSTANCE_PROFILE_ARN ||
410
+ !process.env.AWS_AMI_ID ||
411
+ !process.env.AWS_SNS_TOPIC_ARN
412
+ )
413
+ logAndThrowError(COMMON_ERRORS.CM_WRONG_CONFIGURATION)
414
+
415
+ return {
416
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
417
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
418
+ region: process.env.AWS_REGION || "eu-central-1",
419
+ instanceProfileArn: process.env.AWS_INSTANCE_PROFILE_ARN!,
420
+ amiId: process.env.AWS_AMI_ID!,
421
+ snsTopic: process.env.AWS_SNS_TOPIC_ARN!
422
+ }
423
+ }
424
+
425
+ /**
426
+ * Create an EC2 client object
427
+ * @returns <Promise<EC2Client>> an EC2 client
428
+ */
429
+ export const createEC2Client = async (): Promise<EC2Client> => {
430
+ const { accessKeyId, secretAccessKey, region } = getAWSVariables()
431
+
432
+ const ec2: EC2Client = new EC2Client({
433
+ credentials: {
434
+ accessKeyId,
435
+ secretAccessKey
436
+ },
437
+ region
438
+ })
439
+
440
+ return ec2
441
+ }
442
+
443
+ /**
444
+ * Create an SSM client object
445
+ * @returns <Promise<SSMClient>> an SSM client
446
+ */
447
+ export const createSSMClient = async (): Promise<SSMClient> => {
448
+ const { accessKeyId, secretAccessKey, region } = getAWSVariables()
449
+
450
+ const ssm: SSMClient = new SSMClient({
451
+ credentials: {
452
+ accessKeyId,
453
+ secretAccessKey
454
+ },
455
+ region
456
+ })
457
+
458
+ return ssm
459
+ }
460
+
461
+ /**
462
+ * Get the instance id of the EC2 instance associated with the circuit
463
+ * @param circuitId <string> - the circuit id
464
+ * @returns <Promise<string>> - the EC2 instance id
465
+ */
466
+ export const getEC2InstanceId = async (circuitId: string): Promise<string> => {
467
+ const circuitDoc = await getDocumentById(commonTerms.collections.circuits.name, circuitId)
468
+
469
+ const circuitData = circuitDoc.data()
470
+
471
+ const { vmInstanceId } = circuitData!
472
+
473
+ return vmInstanceId
474
+ }
@@ -0,0 +1 @@
1
+ declare module "@bandada/api-sdk"
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Log levels.
3
+ * @notice useful to discriminate the log level for message printing.
4
+ * @enum {string}
5
+ */
6
+ export enum LogLevel {
7
+ INFO = "INFO",
8
+ DEBUG = "DEBUG",
9
+ WARN = "WARN",
10
+ ERROR = "ERROR",
11
+ LOG = "LOG"
12
+ }
@@ -0,0 +1,200 @@
1
+ import { CeremonyInputData, CircuitDocument, ETagWithPartNumber } from "@devtion/actions"
2
+ import type { Groth16Proof, PublicSignals } from "snarkjs"
3
+
4
+ /**
5
+ * Group all the necessary data needed for running the `setupCeremony` cloud function.
6
+ * @typedef {Object} SetupCeremonyData
7
+ * @property {CeremonyInputData} ceremonyInputData - the necessary input data for setup a new ceremony.
8
+ * @property {string} ceremonyPrefix - the ceremony prefix.
9
+ * @property {Array<CircuitDocument>} circuits - the necessary input data for setup the related ceremony circuits.
10
+ */
11
+ export type SetupCeremonyData = {
12
+ ceremonyInputData: CeremonyInputData
13
+ ceremonyPrefix: string
14
+ circuits: Array<CircuitDocument>
15
+ }
16
+
17
+ /**
18
+ * Group all the necessary data needed for running the `createBucket` cloud function.
19
+ * @typedef {Object} CreateBucketData
20
+ * @property {string} bucketName - the name of the bucket.
21
+ */
22
+ export type CreateBucketData = {
23
+ bucketName: string
24
+ }
25
+
26
+ /**
27
+ * Group all the necessary data needed for running the `checkIfObjectExist` or `generateGetObjectPreSignedUrl` cloud functions.
28
+ * @typedef {Object} BucketAndObjectKeyData
29
+ * @property {string} bucketName - the name of the bucket.
30
+ * @property {string} objectKey - the unique key to identify the object inside the given AWS S3 bucket.
31
+ */
32
+ export type BucketAndObjectKeyData = {
33
+ bucketName: string
34
+ objectKey: string
35
+ }
36
+
37
+ /**
38
+ * Group all the necessary data needed for running the `startMultiPartUpload` cloud function.
39
+ * @typedef {Object} StartMultiPartUploadData
40
+ * @property {string} bucketName - the name of the bucket.
41
+ * @property {string} objectKey - the unique key to identify the object inside the given AWS S3 bucket.
42
+ * @property {string} ceremonyId - the prefix of the ceremony.
43
+ */
44
+ export type StartMultiPartUploadData = BucketAndObjectKeyData & {
45
+ ceremonyId?: string
46
+ }
47
+
48
+ /**
49
+ * Group all the necessary data needed for running the `generatePreSignedUrlsParts` cloud function.
50
+ * @typedef {Object} GeneratePreSignedUrlsPartsData
51
+ * @property {string} bucketName - the name of the bucket.
52
+ * @property {string} objectKey - the unique key to identify the object inside the given AWS S3 bucket.
53
+ * @property {string} uploadId - the identifier of the initiated multi-part upload.
54
+ * @property {number} numberOfParts - the amount of chunks for which pre-signed urls are to be generated.
55
+ * @property {string} ceremonyId - the prefix of the ceremony.
56
+ */
57
+ export type GeneratePreSignedUrlsPartsData = BucketAndObjectKeyData & {
58
+ uploadId: string
59
+ numberOfParts: number
60
+ ceremonyId?: string
61
+ }
62
+
63
+ /**
64
+ * Group all the necessary data needed for running the `completeMultiPartUpload` cloud function.
65
+ * @typedef {Object} GeneratePreSignedUrlsPartsData
66
+ * @property {string} bucketName - the name of the bucket.
67
+ * @property {string} objectKey - the unique key to identify the object inside the given AWS S3 bucket.
68
+ * @property {string} uploadId - the identifier of the initiated multi-part upload.
69
+ * @property {Array<ETagWithPartNumber>} parts - the chunks of the file related to the multi-part upload.
70
+ * @property {string} [ceremonyId] - the unique identifier of the ceremony.
71
+ */
72
+ export type CompleteMultiPartUploadData = BucketAndObjectKeyData & {
73
+ uploadId: string
74
+ parts: Array<ETagWithPartNumber>
75
+ ceremonyId?: string
76
+ }
77
+
78
+ /**
79
+ * Group all the necessary data needed for running the `permanentlyStoreCurrentContributionTimeAndHash` cloud function.
80
+ * @typedef {Object} PermanentlyStoreCurrentContributionTimeAndHash
81
+ * @property {string} ceremonyId - the unique identifier of the ceremony.
82
+ * @property {number} contributionComputationTime - the time spent by the contributor to compute the contribution.
83
+ * @property {string} contributionHash - the hash of the contribution.
84
+ */
85
+ export type PermanentlyStoreCurrentContributionTimeAndHash = {
86
+ ceremonyId: string
87
+ contributionComputationTime: number
88
+ contributionHash: string
89
+ }
90
+
91
+ /**
92
+ * Group all the necessary data needed for running the `temporaryStoreCurrentContributionMultiPartUploadId` cloud function.
93
+ * @typedef {Object} TemporaryStoreCurrentContributionMultiPartUploadId
94
+ * @property {string} ceremonyId - the unique identifier of the ceremony.
95
+ * @property {number} uploadId - the unique identifier of the already started multi-part upload.
96
+ */
97
+ export type TemporaryStoreCurrentContributionMultiPartUploadId = {
98
+ ceremonyId: string
99
+ uploadId: string
100
+ }
101
+
102
+ /**
103
+ * Group all the necessary data needed for running the `temporaryStoreCurrentContributionUploadedChunkData` cloud function.
104
+ * @typedef {Object} TemporaryStoreCurrentContributionUploadedChunkData
105
+ * @property {string} ceremonyId - the unique identifier of the ceremony.
106
+ * @property {number} uploadId - the unique identifier of the already started multi-part upload.
107
+ */
108
+ export type TemporaryStoreCurrentContributionUploadedChunkData = {
109
+ ceremonyId: string
110
+ chunk: ETagWithPartNumber
111
+ }
112
+
113
+ /**
114
+ * Group all the necessary data needed for running the `verifycontribution` cloud function.
115
+ * @typedef {Object} VerifyContributionData
116
+ * @property {string} ceremonyId - the unique identifier of the ceremony.
117
+ * @property {string} circuitId - the unique identifier of the circuit.
118
+ * @property {string} bucketName - the name of the bucket.
119
+ * @property {string} contributorOrCoordinatorIdentifier - the identifier of the contributor or coordinator (only when finalizing).
120
+ */
121
+ export type VerifyContributionData = {
122
+ ceremonyId: string
123
+ circuitId: string
124
+ bucketName: string
125
+ contributorOrCoordinatorIdentifier: string
126
+ }
127
+
128
+ /**
129
+ * Group all the necessary data needed for running the `finalizeCircuit` cloud function.
130
+ * @typedef {Object} FinalizeCircuitData
131
+ * @property {string} ceremonyId - the unique identifier of the ceremony.
132
+ * @property {string} circuitId - the unique identifier of the circuit.
133
+ * @property {string} bucketName - the name of the bucket.
134
+ * @property {string} beacon - the value used to compute the final contribution while finalizing the ceremony.
135
+ */
136
+ export type FinalizeCircuitData = {
137
+ ceremonyId: string
138
+ circuitId: string
139
+ bucketName: string
140
+ beacon: string
141
+ }
142
+
143
+ /**
144
+ * Group all the necessary data needed for running the `bandadaValidateProof` cloud function.
145
+ * @typedef {Object} BandadaValidateProof
146
+ * @property {string} merkleTreeRoot - the merkle tree root of the group.
147
+ * @property {string} nullifierHash - the nullifier hash of the member.
148
+ * @property {string} externalNullifier - the external nullifier of the member.
149
+ * @property {PackedProof} proof - the packed proof generated on the client.
150
+ */
151
+ export type BandadaValidateProof = {
152
+ proof: Groth16Proof
153
+ publicSignals: PublicSignals
154
+ }
155
+
156
+ /**
157
+ * Define the return object of the function that verifies the Bandada membership and proof.
158
+ * @typedef {Object} VerifiedBandadaResponse
159
+ * @property {boolean} valid - true if the proof is valid and the user is a member of the group; otherwise false.
160
+ * @property {string} message - a message describing the result of the verification.
161
+ * @property {string} token - the custom access token.
162
+ */
163
+ export type VerifiedBandadaResponse = {
164
+ valid: boolean
165
+ message: string
166
+ token: string
167
+ }
168
+
169
+ /**
170
+ * Define the check nonce object for the cloud function
171
+ * @typedef {Object} CheckNonceOfSIWEAddressRequest
172
+ * @property {string} auth0Token - token from the device flow authentication
173
+ */
174
+ export type CheckNonceOfSIWEAddressRequest = {
175
+ auth0Token: string
176
+ }
177
+
178
+ /**
179
+ * Define the check nonce response object of the cloud function
180
+ * @typedef {Object} CheckNonceOfSIWEAddressResponse
181
+ * @property {boolean} valid - if the checking result was valid or not
182
+ * @property {string} message - informative message
183
+ * @property {string} token - token to sign in
184
+ */
185
+ export type CheckNonceOfSIWEAddressResponse = {
186
+ valid: boolean
187
+ message?: string
188
+ token?: string
189
+ }
190
+ /**
191
+ * Define the response from auth0 /userinfo endpoint
192
+ *
193
+ */
194
+ export type Auth0UserInfo = {
195
+ sub: string
196
+ nickname: string
197
+ name: string
198
+ picture: string
199
+ updated_at: string
200
+ }