@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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +83 -0
  3. package/dist/index.mjs +2608 -0
  4. package/dist/index.node.js +2714 -0
  5. package/dist/types/hardhat.config.d.ts +6 -0
  6. package/dist/types/hardhat.config.d.ts.map +1 -0
  7. package/dist/types/src/helpers/authentication.d.ts +21 -0
  8. package/dist/types/src/helpers/authentication.d.ts.map +1 -0
  9. package/dist/types/src/helpers/constants.d.ts +194 -0
  10. package/dist/types/src/helpers/constants.d.ts.map +1 -0
  11. package/dist/types/src/helpers/contracts.d.ts +57 -0
  12. package/dist/types/src/helpers/contracts.d.ts.map +1 -0
  13. package/dist/types/src/helpers/crypto.d.ts +27 -0
  14. package/dist/types/src/helpers/crypto.d.ts.map +1 -0
  15. package/dist/types/src/helpers/database.d.ts +105 -0
  16. package/dist/types/src/helpers/database.d.ts.map +1 -0
  17. package/dist/types/src/helpers/functions.d.ts +145 -0
  18. package/dist/types/src/helpers/functions.d.ts.map +1 -0
  19. package/dist/types/src/helpers/security.d.ts +10 -0
  20. package/dist/types/src/helpers/security.d.ts.map +1 -0
  21. package/dist/types/src/helpers/services.d.ts +38 -0
  22. package/dist/types/src/helpers/services.d.ts.map +1 -0
  23. package/dist/types/src/helpers/storage.d.ts +121 -0
  24. package/dist/types/src/helpers/storage.d.ts.map +1 -0
  25. package/dist/types/src/helpers/tasks.d.ts +2 -0
  26. package/dist/types/src/helpers/tasks.d.ts.map +1 -0
  27. package/dist/types/src/helpers/utils.d.ts +139 -0
  28. package/dist/types/src/helpers/utils.d.ts.map +1 -0
  29. package/dist/types/src/helpers/verification.d.ts +95 -0
  30. package/dist/types/src/helpers/verification.d.ts.map +1 -0
  31. package/dist/types/src/helpers/vm.d.ts +112 -0
  32. package/dist/types/src/helpers/vm.d.ts.map +1 -0
  33. package/dist/types/src/index.d.ts +15 -0
  34. package/dist/types/src/index.d.ts.map +1 -0
  35. package/dist/types/src/types/enums.d.ts +133 -0
  36. package/dist/types/src/types/enums.d.ts.map +1 -0
  37. package/dist/types/src/types/index.d.ts +603 -0
  38. package/dist/types/src/types/index.d.ts.map +1 -0
  39. package/package.json +87 -0
  40. package/src/helpers/authentication.ts +37 -0
  41. package/src/helpers/constants.ts +312 -0
  42. package/src/helpers/contracts.ts +268 -0
  43. package/src/helpers/crypto.ts +55 -0
  44. package/src/helpers/database.ts +221 -0
  45. package/src/helpers/functions.ts +438 -0
  46. package/src/helpers/security.ts +86 -0
  47. package/src/helpers/services.ts +83 -0
  48. package/src/helpers/storage.ts +329 -0
  49. package/src/helpers/tasks.ts +56 -0
  50. package/src/helpers/utils.ts +743 -0
  51. package/src/helpers/verification.ts +354 -0
  52. package/src/helpers/vm.ts +392 -0
  53. package/src/index.ts +162 -0
  54. package/src/types/enums.ts +141 -0
  55. 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
+ }