@devtion/actions 0.0.0-7e983e3
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/LICENSE +21 -0
- package/README.md +83 -0
- package/dist/index.mjs +2608 -0
- package/dist/index.node.js +2714 -0
- package/dist/types/hardhat.config.d.ts +6 -0
- package/dist/types/hardhat.config.d.ts.map +1 -0
- package/dist/types/src/helpers/authentication.d.ts +21 -0
- package/dist/types/src/helpers/authentication.d.ts.map +1 -0
- package/dist/types/src/helpers/constants.d.ts +194 -0
- package/dist/types/src/helpers/constants.d.ts.map +1 -0
- package/dist/types/src/helpers/contracts.d.ts +57 -0
- package/dist/types/src/helpers/contracts.d.ts.map +1 -0
- package/dist/types/src/helpers/crypto.d.ts +27 -0
- package/dist/types/src/helpers/crypto.d.ts.map +1 -0
- package/dist/types/src/helpers/database.d.ts +105 -0
- package/dist/types/src/helpers/database.d.ts.map +1 -0
- package/dist/types/src/helpers/functions.d.ts +145 -0
- package/dist/types/src/helpers/functions.d.ts.map +1 -0
- package/dist/types/src/helpers/security.d.ts +10 -0
- package/dist/types/src/helpers/security.d.ts.map +1 -0
- package/dist/types/src/helpers/services.d.ts +38 -0
- package/dist/types/src/helpers/services.d.ts.map +1 -0
- package/dist/types/src/helpers/storage.d.ts +121 -0
- package/dist/types/src/helpers/storage.d.ts.map +1 -0
- package/dist/types/src/helpers/tasks.d.ts +2 -0
- package/dist/types/src/helpers/tasks.d.ts.map +1 -0
- package/dist/types/src/helpers/utils.d.ts +139 -0
- package/dist/types/src/helpers/utils.d.ts.map +1 -0
- package/dist/types/src/helpers/verification.d.ts +95 -0
- package/dist/types/src/helpers/verification.d.ts.map +1 -0
- package/dist/types/src/helpers/vm.d.ts +112 -0
- package/dist/types/src/helpers/vm.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +15 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/types/enums.d.ts +133 -0
- package/dist/types/src/types/enums.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +603 -0
- package/dist/types/src/types/index.d.ts.map +1 -0
- package/package.json +87 -0
- package/src/helpers/authentication.ts +37 -0
- package/src/helpers/constants.ts +312 -0
- package/src/helpers/contracts.ts +268 -0
- package/src/helpers/crypto.ts +55 -0
- package/src/helpers/database.ts +221 -0
- package/src/helpers/functions.ts +438 -0
- package/src/helpers/security.ts +86 -0
- package/src/helpers/services.ts +83 -0
- package/src/helpers/storage.ts +329 -0
- package/src/helpers/tasks.ts +56 -0
- package/src/helpers/utils.ts +743 -0
- package/src/helpers/verification.ts +354 -0
- package/src/helpers/vm.ts +392 -0
- package/src/index.ts +162 -0
- package/src/types/enums.ts +141 -0
- package/src/types/index.ts +650 -0
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
import { Functions, httpsCallable, httpsCallableFromURL } from "firebase/functions"
|
|
2
|
+
import { DocumentSnapshot, onSnapshot } from "firebase/firestore"
|
|
3
|
+
import { CeremonyInputData, CircuitDocument, ETagWithPartNumber, FirebaseDocumentInfo } from "../types/index"
|
|
4
|
+
import { commonTerms } from "./constants"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Setup a new ceremony by calling the related cloud function.
|
|
8
|
+
* @param functions <Functions> - the Firebase cloud functions object instance.
|
|
9
|
+
* @param ceremonyInputData <CeremonyInputData> - the input data of the ceremony.
|
|
10
|
+
* @param ceremonyPrefix <string> - the prefix of the ceremony.
|
|
11
|
+
* @param circuits <Circuit[]> - the circuits data.
|
|
12
|
+
* @returns Promise<string> - the unique identifier of the created ceremony.
|
|
13
|
+
*/
|
|
14
|
+
export const setupCeremony = async (
|
|
15
|
+
functions: Functions,
|
|
16
|
+
ceremonyInputData: CeremonyInputData,
|
|
17
|
+
ceremonyPrefix: string,
|
|
18
|
+
circuits: CircuitDocument[]
|
|
19
|
+
): Promise<string> => {
|
|
20
|
+
const cf = httpsCallable(functions, commonTerms.cloudFunctionsNames.setupCeremony)
|
|
21
|
+
|
|
22
|
+
const { data: ceremonyId } = await cf({
|
|
23
|
+
ceremonyInputData,
|
|
24
|
+
ceremonyPrefix,
|
|
25
|
+
circuits
|
|
26
|
+
})
|
|
27
|
+
return String(ceremonyId)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Check the user's current participant status for the ceremony
|
|
32
|
+
* @param functions <Functions> - the Firebase cloud functions object instance.
|
|
33
|
+
* @param ceremonyId <string> - the unique identifier of the ceremony.
|
|
34
|
+
* @returns <boolean> - true when participant is able to contribute; otherwise false.
|
|
35
|
+
*/
|
|
36
|
+
export const checkParticipantForCeremony = async (functions: Functions, ceremonyId: string): Promise<any> => {
|
|
37
|
+
const cf = httpsCallable(functions, commonTerms.cloudFunctionsNames.checkParticipantForCeremony)
|
|
38
|
+
|
|
39
|
+
const { data } = await cf({ ceremonyId })
|
|
40
|
+
|
|
41
|
+
return data
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Progress the participant to the next circuit preparing for the next contribution.
|
|
46
|
+
* @param functions <Functions> - the Firebase cloud functions object instance.
|
|
47
|
+
* @param ceremonyId <string> - the unique identifier of the ceremony.
|
|
48
|
+
*/
|
|
49
|
+
export const progressToNextCircuitForContribution = async (functions: Functions, ceremonyId: string): Promise<void> => {
|
|
50
|
+
const cf = httpsCallable(functions, commonTerms.cloudFunctionsNames.progressToNextCircuitForContribution)
|
|
51
|
+
|
|
52
|
+
await cf({
|
|
53
|
+
ceremonyId
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Resume the contributor circuit contribution from scratch after the timeout expiration.
|
|
59
|
+
* @param functions <Functions> - the Firebase cloud functions object instance.
|
|
60
|
+
* @param ceremonyId <string> - the unique identifier of the ceremony.
|
|
61
|
+
*/
|
|
62
|
+
export const resumeContributionAfterTimeoutExpiration = async (
|
|
63
|
+
functions: Functions,
|
|
64
|
+
ceremonyId: string
|
|
65
|
+
): Promise<void> => {
|
|
66
|
+
const cf = httpsCallable(functions, commonTerms.cloudFunctionsNames.resumeContributionAfterTimeoutExpiration)
|
|
67
|
+
|
|
68
|
+
await cf({
|
|
69
|
+
ceremonyId
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Make a request to create a new AWS S3 bucket for a ceremony.
|
|
75
|
+
* @param functions <Functions> - the Firebase cloud functions object instance.
|
|
76
|
+
* @param bucketName <string> - the name of the ceremony bucket.
|
|
77
|
+
*/
|
|
78
|
+
export const createS3Bucket = async (functions: Functions, bucketName: string) => {
|
|
79
|
+
const cf = httpsCallable(functions, commonTerms.cloudFunctionsNames.createBucket)
|
|
80
|
+
|
|
81
|
+
await cf({ bucketName })
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Return a pre-signed url for a given object contained inside the provided AWS S3 bucket in order to perform a GET request.
|
|
86
|
+
* @param functions <Functions> - the Firebase cloud functions object instance.
|
|
87
|
+
* @param bucketName <string> - the name of the ceremony bucket.
|
|
88
|
+
* @param objectKey <string> - the storage path that locates the artifact to be downloaded in the bucket.
|
|
89
|
+
* @returns <Promise<string>> - the pre-signed url w/ GET request permissions for specified object key.
|
|
90
|
+
*/
|
|
91
|
+
export const generateGetObjectPreSignedUrl = async (
|
|
92
|
+
functions: Functions,
|
|
93
|
+
bucketName: string,
|
|
94
|
+
objectKey: string
|
|
95
|
+
): Promise<string> => {
|
|
96
|
+
const cf = httpsCallable(functions, commonTerms.cloudFunctionsNames.generateGetObjectPreSignedUrl)
|
|
97
|
+
|
|
98
|
+
const { data: getPreSignedUrl } = await cf({
|
|
99
|
+
bucketName,
|
|
100
|
+
objectKey
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
return String(getPreSignedUrl)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Progress the participant to the next circuit preparing for the next contribution.
|
|
108
|
+
* @param functions <Functions> - the Firebase cloud functions object instance.
|
|
109
|
+
* @param ceremonyId <string> - the unique identifier of the ceremony.
|
|
110
|
+
*/
|
|
111
|
+
export const progressToNextContributionStep = async (functions: Functions, ceremonyId: string) => {
|
|
112
|
+
const cf = httpsCallable(functions, commonTerms.cloudFunctionsNames.progressToNextContributionStep)
|
|
113
|
+
|
|
114
|
+
await cf({
|
|
115
|
+
ceremonyId
|
|
116
|
+
})
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Write the information about current contribution hash and computation time for the current contributor.
|
|
121
|
+
* @param functions <Functions> - the Firebase cloud functions object instance.
|
|
122
|
+
* @param ceremonyId <string> - the unique identifier of the ceremony.
|
|
123
|
+
* @param contributionComputationTime <number> - the time when it was computed
|
|
124
|
+
* @param contributingHash <string> - the hash of the contribution
|
|
125
|
+
*/
|
|
126
|
+
export const permanentlyStoreCurrentContributionTimeAndHash = async (
|
|
127
|
+
functions: Functions,
|
|
128
|
+
ceremonyId: string,
|
|
129
|
+
contributionComputationTime: number,
|
|
130
|
+
contributionHash: string
|
|
131
|
+
) => {
|
|
132
|
+
const cf = httpsCallable(functions, commonTerms.cloudFunctionsNames.permanentlyStoreCurrentContributionTimeAndHash)
|
|
133
|
+
await cf({
|
|
134
|
+
ceremonyId,
|
|
135
|
+
contributionComputationTime,
|
|
136
|
+
contributionHash
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Start a new multi-part upload for a specific object in the given AWS S3 bucket.
|
|
142
|
+
* @param functions <Functions> - the Firebase cloud functions object instance.
|
|
143
|
+
* @param bucketName <string> - the name of the ceremony bucket.
|
|
144
|
+
* @param objectKey <string> - the storage path that locates the artifact to be downloaded in the bucket.
|
|
145
|
+
* @param ceremonyId <string> - the unique identifier of the ceremony.
|
|
146
|
+
* @returns Promise<string> - the multi-part upload id.
|
|
147
|
+
*/
|
|
148
|
+
export const openMultiPartUpload = async (
|
|
149
|
+
functions: Functions,
|
|
150
|
+
bucketName: string,
|
|
151
|
+
objectKey: string,
|
|
152
|
+
ceremonyId?: string
|
|
153
|
+
): Promise<string> => {
|
|
154
|
+
const cf = httpsCallable(functions, commonTerms.cloudFunctionsNames.startMultiPartUpload)
|
|
155
|
+
|
|
156
|
+
const { data: uploadId } = await cf({
|
|
157
|
+
bucketName,
|
|
158
|
+
objectKey,
|
|
159
|
+
ceremonyId
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
return String(uploadId)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Write temporary information about the unique identifier about the opened multi-part upload to eventually resume the contribution.
|
|
167
|
+
* @param functions <Functions> - the Firebase cloud functions object instance.
|
|
168
|
+
* @param ceremonyId <string> - the unique identifier of the ceremony.
|
|
169
|
+
* @param uploadId <string> - the unique identifier of the multi-part upload.
|
|
170
|
+
*/
|
|
171
|
+
export const temporaryStoreCurrentContributionMultiPartUploadId = async (
|
|
172
|
+
functions: Functions,
|
|
173
|
+
ceremonyId: string,
|
|
174
|
+
uploadId: string
|
|
175
|
+
) => {
|
|
176
|
+
const cf = httpsCallable(
|
|
177
|
+
functions,
|
|
178
|
+
commonTerms.cloudFunctionsNames.temporaryStoreCurrentContributionMultiPartUploadId
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
await cf({
|
|
182
|
+
ceremonyId,
|
|
183
|
+
uploadId
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Write temporary information about the etags and part numbers for each uploaded chunk in order to make the upload resumable from last chunk.
|
|
189
|
+
* @param functions <Functions> - the Firebase cloud functions object instance.
|
|
190
|
+
* @param ceremonyId <string> - the unique identifier of the ceremony.
|
|
191
|
+
* @param chunk <ETagWithPartNumber> - the information about the already uploaded chunk.
|
|
192
|
+
*/
|
|
193
|
+
export const temporaryStoreCurrentContributionUploadedChunkData = async (
|
|
194
|
+
functions: Functions,
|
|
195
|
+
ceremonyId: string,
|
|
196
|
+
chunk: ETagWithPartNumber
|
|
197
|
+
) => {
|
|
198
|
+
const cf = httpsCallable(
|
|
199
|
+
functions,
|
|
200
|
+
commonTerms.cloudFunctionsNames.temporaryStoreCurrentContributionUploadedChunkData
|
|
201
|
+
)
|
|
202
|
+
await cf({
|
|
203
|
+
ceremonyId,
|
|
204
|
+
chunk
|
|
205
|
+
})
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Generate a new pre-signed url for each chunk related to a started multi-part upload.
|
|
210
|
+
* @param functions <Functions> - the Firebase cloud functions object instance.
|
|
211
|
+
* @param bucketName <string> - the name of the ceremony bucket.
|
|
212
|
+
* @param objectKey <string> - the storage path that locates the artifact to be downloaded in the bucket.
|
|
213
|
+
* @param uploadId <string> - the unique identifier of the multi-part upload.
|
|
214
|
+
* @param numberOfChunks <number> - the number of pre-signed urls to be generated.
|
|
215
|
+
* @param ceremonyId <string> - the unique identifier of the ceremony.
|
|
216
|
+
* @returns Promise<Array<string>> - the set of pre-signed urls (one for each chunk).
|
|
217
|
+
*/
|
|
218
|
+
export const generatePreSignedUrlsParts = async (
|
|
219
|
+
functions: Functions,
|
|
220
|
+
bucketName: string,
|
|
221
|
+
objectKey: string,
|
|
222
|
+
uploadId: string,
|
|
223
|
+
numberOfParts: number,
|
|
224
|
+
ceremonyId?: string
|
|
225
|
+
): Promise<Array<string>> => {
|
|
226
|
+
const cf = httpsCallable(functions, commonTerms.cloudFunctionsNames.generatePreSignedUrlsParts)
|
|
227
|
+
|
|
228
|
+
const { data: chunksUrls }: any = await cf({
|
|
229
|
+
bucketName,
|
|
230
|
+
objectKey,
|
|
231
|
+
uploadId,
|
|
232
|
+
numberOfParts,
|
|
233
|
+
ceremonyId
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
return chunksUrls
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Complete a multi-part upload for a specific object in the given AWS S3 bucket.
|
|
241
|
+
* @param functions <Functions> - the Firebase cloud functions object instance.
|
|
242
|
+
* @param bucketName <string> - the name of the ceremony bucket.
|
|
243
|
+
* @param objectKey <string> - the storage path that locates the artifact to be downloaded in the bucket.
|
|
244
|
+
* @param uploadId <string> - the unique identifier of the multi-part upload.
|
|
245
|
+
* @param parts Array<ETagWithPartNumber> - the completed .
|
|
246
|
+
* @param ceremonyId <string> - the unique identifier of the ceremony.
|
|
247
|
+
* @returns Promise<string> - the location of the uploaded ceremony artifact.
|
|
248
|
+
*/
|
|
249
|
+
export const completeMultiPartUpload = async (
|
|
250
|
+
functions: Functions,
|
|
251
|
+
bucketName: string,
|
|
252
|
+
objectKey: string,
|
|
253
|
+
uploadId: string,
|
|
254
|
+
parts: Array<ETagWithPartNumber>,
|
|
255
|
+
ceremonyId?: string
|
|
256
|
+
): Promise<string> => {
|
|
257
|
+
// Call completeMultiPartUpload() Cloud Function.
|
|
258
|
+
const cf = httpsCallable(functions, commonTerms.cloudFunctionsNames.completeMultiPartUpload)
|
|
259
|
+
|
|
260
|
+
const { data: location }: any = await cf({
|
|
261
|
+
bucketName,
|
|
262
|
+
objectKey,
|
|
263
|
+
uploadId,
|
|
264
|
+
parts,
|
|
265
|
+
ceremonyId
|
|
266
|
+
})
|
|
267
|
+
|
|
268
|
+
return String(location)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Check if a specified object exist in a given AWS S3 bucket.
|
|
273
|
+
* @param functions <Functions> - the Firebase cloud functions object instance.
|
|
274
|
+
* @param bucketName <string> - the name of the ceremony bucket.
|
|
275
|
+
* @param objectKey <string> - the storage path that locates the artifact to be downloaded in the bucket.
|
|
276
|
+
* @returns <Promise<string>> - true if and only if the object exists, otherwise false.
|
|
277
|
+
*/
|
|
278
|
+
export const checkIfObjectExist = async (
|
|
279
|
+
functions: Functions,
|
|
280
|
+
bucketName: string,
|
|
281
|
+
objectKey: string
|
|
282
|
+
): Promise<boolean> => {
|
|
283
|
+
const cf = httpsCallable(functions, commonTerms.cloudFunctionsNames.checkIfObjectExist)
|
|
284
|
+
|
|
285
|
+
const { data: doesObjectExist }: any = await cf({
|
|
286
|
+
bucketName,
|
|
287
|
+
objectKey
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
return doesObjectExist
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Request to verify the newest contribution for the circuit.
|
|
295
|
+
* @param functions <Functions> - the Firebase cloud functions object instance.
|
|
296
|
+
* @param ceremonyId <string> - the unique identifier of the ceremony.
|
|
297
|
+
* @param circuit <FirebaseDocumentInfo> - the document info about the circuit.
|
|
298
|
+
* @param bucketName <string> - the name of the ceremony bucket.
|
|
299
|
+
* @param contributorOrCoordinatorIdentifier <string> - the identifier of the contributor or coordinator (only when finalizing).
|
|
300
|
+
* @param verifyContributionCloudFunctionEndpoint <string> - the endpoint (direct url) necessary to call the V2 Cloud Function.
|
|
301
|
+
* @returns <Promise<void>> -
|
|
302
|
+
*/
|
|
303
|
+
export const verifyContribution = async (
|
|
304
|
+
functions: Functions,
|
|
305
|
+
ceremonyId: string,
|
|
306
|
+
circuit: FirebaseDocumentInfo, // any just to avoid breaking the tests.
|
|
307
|
+
bucketName: string,
|
|
308
|
+
contributorOrCoordinatorIdentifier: string,
|
|
309
|
+
verifyContributionCloudFunctionEndpoint: string
|
|
310
|
+
): Promise<void> => {
|
|
311
|
+
const cf = httpsCallableFromURL(functions, verifyContributionCloudFunctionEndpoint, {
|
|
312
|
+
timeout: 3600000 // max timeout 60 minutes.
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* @dev Force a race condition to fix #57.
|
|
317
|
+
* TL;DR if the cloud function does not return despite having finished its execution, we use
|
|
318
|
+
* a listener on the circuit, we check and retrieve the info about the correct execution and
|
|
319
|
+
* return it manually. In other cases, it will be the function that returns either a timeout in case it
|
|
320
|
+
* remains in execution for too long.
|
|
321
|
+
*/
|
|
322
|
+
await Promise.race([
|
|
323
|
+
cf({
|
|
324
|
+
ceremonyId,
|
|
325
|
+
circuitId: circuit.id,
|
|
326
|
+
contributorOrCoordinatorIdentifier,
|
|
327
|
+
bucketName
|
|
328
|
+
}),
|
|
329
|
+
new Promise((resolve): any => {
|
|
330
|
+
setTimeout(() => {
|
|
331
|
+
const unsubscribeToCeremonyCircuitListener = onSnapshot(
|
|
332
|
+
circuit.ref,
|
|
333
|
+
async (changedCircuit: DocumentSnapshot) => {
|
|
334
|
+
// Check data.
|
|
335
|
+
if (!circuit.data || !changedCircuit.data())
|
|
336
|
+
throw Error(`Unable to retrieve circuit data from the ceremony.`)
|
|
337
|
+
|
|
338
|
+
// Extract data.
|
|
339
|
+
const { avgTimings: changedAvgTimings, waitingQueue: changedWaitingQueue } =
|
|
340
|
+
changedCircuit.data()!
|
|
341
|
+
const {
|
|
342
|
+
contributionComputation: changedContributionComputation,
|
|
343
|
+
fullContribution: changedFullContribution,
|
|
344
|
+
verifyCloudFunction: changedVerifyCloudFunction
|
|
345
|
+
} = changedAvgTimings
|
|
346
|
+
const {
|
|
347
|
+
failedContributions: changedFailedContributions,
|
|
348
|
+
completedContributions: changedCompletedContributions
|
|
349
|
+
} = changedWaitingQueue
|
|
350
|
+
|
|
351
|
+
const { avgTimings: prevAvgTimings, waitingQueue: prevWaitingQueue } = changedCircuit.data()!
|
|
352
|
+
const {
|
|
353
|
+
contributionComputation: prevContributionComputation,
|
|
354
|
+
fullContribution: prevFullContribution,
|
|
355
|
+
verifyCloudFunction: prevVerifyCloudFunction
|
|
356
|
+
} = prevAvgTimings
|
|
357
|
+
const {
|
|
358
|
+
failedContributions: prevFailedContributions,
|
|
359
|
+
completedContributions: prevCompletedContributions
|
|
360
|
+
} = prevWaitingQueue
|
|
361
|
+
|
|
362
|
+
// Pre-conditions.
|
|
363
|
+
const invalidContribution = prevFailedContributions === changedFailedContributions - 1
|
|
364
|
+
const validContribution = prevCompletedContributions === changedCompletedContributions - 1
|
|
365
|
+
const avgTimeUpdates =
|
|
366
|
+
prevContributionComputation !== changedContributionComputation &&
|
|
367
|
+
prevFullContribution !== changedFullContribution &&
|
|
368
|
+
prevVerifyCloudFunction !== changedVerifyCloudFunction
|
|
369
|
+
|
|
370
|
+
if ((invalidContribution || validContribution) && avgTimeUpdates) {
|
|
371
|
+
resolve({})
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
// Unsubscribe from listener.
|
|
377
|
+
unsubscribeToCeremonyCircuitListener()
|
|
378
|
+
}, 3600000 - 1000) // 59:59 throws 1s before max time for CF execution.
|
|
379
|
+
})
|
|
380
|
+
])
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Prepare the coordinator for the finalization of the ceremony.
|
|
385
|
+
* @param functions <Functions> - the Firebase cloud functions object instance.
|
|
386
|
+
* @param ceremonyId <string> - the unique identifier of the ceremony.
|
|
387
|
+
* @returns <Promise<boolean>> - true when the coordinator is ready for finalization; otherwise false.
|
|
388
|
+
*/
|
|
389
|
+
export const checkAndPrepareCoordinatorForFinalization = async (
|
|
390
|
+
functions: Functions,
|
|
391
|
+
ceremonyId: string
|
|
392
|
+
): Promise<boolean> => {
|
|
393
|
+
const cf = httpsCallable(functions, commonTerms.cloudFunctionsNames.checkAndPrepareCoordinatorForFinalization)
|
|
394
|
+
|
|
395
|
+
const { data: isCoordinatorReadyForCeremonyFinalization }: any = await cf({
|
|
396
|
+
ceremonyId
|
|
397
|
+
})
|
|
398
|
+
|
|
399
|
+
return isCoordinatorReadyForCeremonyFinalization
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Finalize the ceremony circuit.
|
|
404
|
+
* @param functions <Functions> - the Firebase cloud functions object instance.
|
|
405
|
+
* @param ceremonyId <string> - the unique identifier of the ceremony.
|
|
406
|
+
* @param circuitId <string> - the unique identifier of the circuit.
|
|
407
|
+
* @param bucketName <string> - the name of the ceremony bucket.
|
|
408
|
+
* @param beacon <string> - the value used to compute the final contribution while finalizing the ceremony.
|
|
409
|
+
*/
|
|
410
|
+
export const finalizeCircuit = async (
|
|
411
|
+
functions: Functions,
|
|
412
|
+
ceremonyId: string,
|
|
413
|
+
circuitId: any,
|
|
414
|
+
bucketName: string,
|
|
415
|
+
beacon: string
|
|
416
|
+
) => {
|
|
417
|
+
const cf = httpsCallable(functions, commonTerms.cloudFunctionsNames.finalizeCircuit)
|
|
418
|
+
|
|
419
|
+
await cf({
|
|
420
|
+
ceremonyId,
|
|
421
|
+
circuitId,
|
|
422
|
+
bucketName,
|
|
423
|
+
beacon
|
|
424
|
+
})
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Conclude the finalization of the ceremony.
|
|
429
|
+
* @param functions <Functions> - the Firebase cloud functions object instance.
|
|
430
|
+
* @param ceremonyId <string> - the unique identifier of the ceremony.
|
|
431
|
+
*/
|
|
432
|
+
export const finalizeCeremony = async (functions: Functions, ceremonyId: string) => {
|
|
433
|
+
const cf = httpsCallable(functions, commonTerms.cloudFunctionsNames.finalizeCeremony)
|
|
434
|
+
|
|
435
|
+
await cf({
|
|
436
|
+
ceremonyId
|
|
437
|
+
})
|
|
438
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import fetch from "@adobe/node-fetch-retry"
|
|
2
|
+
/**
|
|
3
|
+
* This function will return the number of public repos of a user
|
|
4
|
+
* @param user <string> The username of the user
|
|
5
|
+
* @returns <number> The number of public repos
|
|
6
|
+
*/
|
|
7
|
+
const getNumberOfPublicReposGitHub = async (user: string): Promise<number> => {
|
|
8
|
+
const response = await fetch(`https://api.github.com/user/${user}/repos`, {
|
|
9
|
+
method: "GET",
|
|
10
|
+
headers: {
|
|
11
|
+
Authorization: `token ${process.env.GITHUB_ACCESS_TOKEN!}`
|
|
12
|
+
}
|
|
13
|
+
})
|
|
14
|
+
if (response.status !== 200)
|
|
15
|
+
throw new Error("It was not possible to retrieve the number of public repositories. Please try again.")
|
|
16
|
+
const jsonData: any = await response.json()
|
|
17
|
+
return jsonData.length
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* This function will return the number of followers of a user
|
|
21
|
+
* @param user <string> The username of the user
|
|
22
|
+
* @returns <number> The number of followers
|
|
23
|
+
*/
|
|
24
|
+
const getNumberOfFollowersGitHub = async (user: string): Promise<number> => {
|
|
25
|
+
const response = await fetch(`https://api.github.com/user/${user}/followers`, {
|
|
26
|
+
method: "GET",
|
|
27
|
+
headers: {
|
|
28
|
+
Authorization: `token ${process.env.GITHUB_ACCESS_TOKEN!}`
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
if (response.status !== 200)
|
|
32
|
+
throw new Error("It was not possible to retrieve the number of followers. Please try again.")
|
|
33
|
+
const jsonData: any = await response.json()
|
|
34
|
+
return jsonData.length
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* This function will return the number of following of a user
|
|
38
|
+
* @param user <string> The username of the user
|
|
39
|
+
* @returns <number> The number of following users
|
|
40
|
+
*/
|
|
41
|
+
const getNumberOfFollowingGitHub = async (user: string): Promise<number> => {
|
|
42
|
+
const response = await fetch(`https://api.github.com/user/${user}/following`, {
|
|
43
|
+
method: "GET",
|
|
44
|
+
headers: {
|
|
45
|
+
Authorization: `token ${process.env.GITHUB_ACCESS_TOKEN!}`
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
if (response.status !== 200)
|
|
50
|
+
throw new Error("It was not possible to retrieve the number of following. Please try again.")
|
|
51
|
+
|
|
52
|
+
const jsonData: any = await response.json()
|
|
53
|
+
|
|
54
|
+
return jsonData.length
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* This function will check if the user is reputable enough to be able to use the app
|
|
59
|
+
* @param userLogin <string> The username of the user
|
|
60
|
+
* @param minimumAmountOfFollowing <number> The minimum amount of following the user should have
|
|
61
|
+
* @param minimumAmountOfFollowers <number> The minimum amount of followers the user should have
|
|
62
|
+
* @param minimumAmountOfPublicRepos <number> The minimum amount of public repos the user should have
|
|
63
|
+
* @returns <boolean> True if the user is reputable enough, false otherwise
|
|
64
|
+
*/
|
|
65
|
+
export const githubReputation = async (
|
|
66
|
+
userLogin: string,
|
|
67
|
+
minimumAmountOfFollowing: number,
|
|
68
|
+
minimumAmountOfFollowers: number,
|
|
69
|
+
minimumAmountOfPublicRepos: number
|
|
70
|
+
): Promise<boolean> => {
|
|
71
|
+
if (!process.env.GITHUB_ACCESS_TOKEN)
|
|
72
|
+
throw new Error(
|
|
73
|
+
"The GitHub access token is missing. Please insert a valid token to be used for anti-sybil checks on user registation, and then try again."
|
|
74
|
+
)
|
|
75
|
+
const following = await getNumberOfFollowingGitHub(userLogin)
|
|
76
|
+
const repos = await getNumberOfPublicReposGitHub(userLogin)
|
|
77
|
+
const followers = await getNumberOfFollowersGitHub(userLogin)
|
|
78
|
+
|
|
79
|
+
if (
|
|
80
|
+
following < minimumAmountOfFollowing ||
|
|
81
|
+
repos < minimumAmountOfPublicRepos ||
|
|
82
|
+
followers < minimumAmountOfFollowers
|
|
83
|
+
)
|
|
84
|
+
return false
|
|
85
|
+
return true
|
|
86
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { FirebaseApp, FirebaseOptions, initializeApp } from "firebase/app" // ref https://firebase.google.com/docs/web/setup#access-firebase.
|
|
2
|
+
import { Firestore, getFirestore } from "firebase/firestore"
|
|
3
|
+
import { Functions, getFunctions } from "firebase/functions"
|
|
4
|
+
import { AWSVariables, FirebaseServices } from "../types/index"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* This method initialize a Firebase app if no other app has already been initialized.
|
|
8
|
+
* @param options <FirebaseOptions> - an object w/ every necessary Firebase option to init app.
|
|
9
|
+
* @returns <FirebaseApp> - the initialized Firebase app object.
|
|
10
|
+
*/
|
|
11
|
+
export const initializeFirebaseApp = (options: FirebaseOptions): FirebaseApp => initializeApp(options)
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* This method returns the Firestore database instance associated to the given Firebase application.
|
|
15
|
+
* @param app <FirebaseApp> - the Firebase application.
|
|
16
|
+
* @returns <Firestore> - the Firebase Firestore associated to the application.
|
|
17
|
+
*/
|
|
18
|
+
export const getFirestoreDatabase = (app: FirebaseApp): Firestore => getFirestore(app)
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* This method returns the Cloud Functions instance associated to the given Firebase application.
|
|
22
|
+
* @param app <FirebaseApp> - the Firebase application.
|
|
23
|
+
* @returns <Functions> - the Cloud Functions associated to the application.
|
|
24
|
+
*/
|
|
25
|
+
export const getFirebaseFunctions = (app: FirebaseApp): Functions => getFunctions(app, 'europe-west1')
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Retrieve the configuration variables for the AWS services (S3, EC2).
|
|
29
|
+
* @returns <AWSVariables> - the values of the AWS services configuration variables.
|
|
30
|
+
*/
|
|
31
|
+
export const getAWSVariables = (): AWSVariables => {
|
|
32
|
+
if (
|
|
33
|
+
!process.env.AWS_ACCESS_KEY_ID ||
|
|
34
|
+
!process.env.AWS_SECRET_ACCESS_KEY ||
|
|
35
|
+
!process.env.AWS_REGION ||
|
|
36
|
+
!process.env.AWS_ROLE_ARN ||
|
|
37
|
+
!process.env.AWS_AMI_ID
|
|
38
|
+
)
|
|
39
|
+
throw new Error(
|
|
40
|
+
"Could not retrieve the AWS environment variables. Please, verify your environment configuration and retry"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
|
|
45
|
+
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
|
|
46
|
+
region: process.env.AWS_REGION || "us-east-1",
|
|
47
|
+
roleArn: process.env.AWS_ROLE_ARN!,
|
|
48
|
+
amiId: process.env.AWS_AMI_ID!
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Return the core Firebase services instances (App, Database, Functions).
|
|
54
|
+
* @param apiKey <string> - the API key specified in the application config.
|
|
55
|
+
* @param authDomain <string> - the authDomain string specified in the application config.
|
|
56
|
+
* @param projectId <string> - the projectId specified in the application config.
|
|
57
|
+
* @param messagingSenderId <string> - the messagingSenderId specified in the application config.
|
|
58
|
+
* @param appId <string> - the appId specified in the application config.
|
|
59
|
+
* @returns <Promise<FirebaseServices>>
|
|
60
|
+
*/
|
|
61
|
+
export const initializeFirebaseCoreServices = async (
|
|
62
|
+
apiKey: string,
|
|
63
|
+
authDomain: string,
|
|
64
|
+
projectId: string,
|
|
65
|
+
messagingSenderId: string,
|
|
66
|
+
appId: string
|
|
67
|
+
): Promise<FirebaseServices> => {
|
|
68
|
+
const firebaseApp = initializeFirebaseApp({
|
|
69
|
+
apiKey,
|
|
70
|
+
authDomain,
|
|
71
|
+
projectId,
|
|
72
|
+
messagingSenderId,
|
|
73
|
+
appId
|
|
74
|
+
})
|
|
75
|
+
const firestoreDatabase = getFirestoreDatabase(firebaseApp)
|
|
76
|
+
const firebaseFunctions = getFirebaseFunctions(firebaseApp)
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
firebaseApp,
|
|
80
|
+
firestoreDatabase,
|
|
81
|
+
firebaseFunctions
|
|
82
|
+
}
|
|
83
|
+
}
|