@devtion/backend 0.0.0-bfc9ee4 → 0.0.0-c749be4

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devtion/backend",
3
- "version": "0.0.0-bfc9ee4",
3
+ "version": "0.0.0-c749be4",
4
4
  "description": "MPC Phase 2 backend for Firebase services management",
5
5
  "repository": "git@github.com:privacy-scaling-explorations/p0tion.git",
6
6
  "homepage": "https://github.com/privacy-scaling-explorations/p0tion",
@@ -67,7 +67,7 @@
67
67
  "@aws-sdk/client-ssm": "^3.357.0",
68
68
  "@aws-sdk/middleware-endpoint": "^3.329.0",
69
69
  "@aws-sdk/s3-request-presigner": "^3.329.0",
70
- "@p0tion/actions": "^1.0.5",
70
+ "@devtion/actions": "latest",
71
71
  "blakejs": "^1.2.1",
72
72
  "dotenv": "^16.0.3",
73
73
  "ethers": "5.7.2",
@@ -85,5 +85,5 @@
85
85
  "publishConfig": {
86
86
  "access": "public"
87
87
  },
88
- "gitHead": "b2a3be0c3d0ad2a94270d7a256b5b5acf3b1c47f"
88
+ "gitHead": "b58b49526070e9e95f9d13ebe0f24dd62a08a09d"
89
89
  }
@@ -18,7 +18,7 @@ import {
18
18
  vmBootstrapCommand,
19
19
  vmDependenciesAndCacheArtifactsCommand,
20
20
  vmBootstrapScriptFilename
21
- } from "@p0tion/actions"
21
+ } from "@devtion/actions"
22
22
  import { encode } from "html-entities"
23
23
  import { SetupCeremonyData } from "../types/index"
24
24
  import { COMMON_ERRORS, logAndThrowError, printLog, SPECIFIC_ERRORS } from "../lib/errors"
@@ -146,7 +146,7 @@ export const setupCeremony = functions
146
146
  // Check if using the VM approach for contribution verification.
147
147
  if (circuit.verification.cfOrVm === CircuitContributionVerificationMechanism.VM) {
148
148
  // VM command to be run at the startup.
149
- const startupCommand = vmBootstrapCommand(bucketName)
149
+ const startupCommand = vmBootstrapCommand(`${bucketName}/circuits/${circuit.name!}`)
150
150
 
151
151
  // Get EC2 client.
152
152
  const ec2Client = await createEC2Client()
@@ -165,7 +165,12 @@ export const setupCeremony = functions
165
165
  printLog(`Check VM dependencies and cache artifacts commands ${vmCommands.join("\n")}`, LogLevel.DEBUG)
166
166
 
167
167
  // Upload the post-startup commands script file.
168
- await uploadFileToBucketNoFile(bucketName, vmBootstrapScriptFilename, vmCommands.join("\n"))
168
+ printLog(`Uploading VM post-startup commands script file ${vmBootstrapScriptFilename}`, LogLevel.DEBUG)
169
+ await uploadFileToBucketNoFile(
170
+ bucketName,
171
+ `circuits/${circuit.name!}/${vmBootstrapScriptFilename}`,
172
+ vmCommands.join("\n")
173
+ )
169
174
 
170
175
  // Compute the VM disk space requirement (in GB).
171
176
  const vmDiskSize = computeDiskSizeForVM(circuit.zKeySizeInBytes!, circuit.metadata?.pot!)
@@ -37,12 +37,14 @@ import {
37
37
  createCustomLoggerForFile,
38
38
  retrieveCommandStatus,
39
39
  stopEC2Instance
40
- } from "@p0tion/actions"
40
+ } from "@devtion/actions"
41
41
  import { zKey } from "snarkjs"
42
42
  import { CommandInvocationStatus, SSMClient } from "@aws-sdk/client-ssm"
43
+ import { EC2Client } from "@aws-sdk/client-ec2"
44
+ import { HttpsError } from "firebase-functions/v2/https"
43
45
  import { FinalizeCircuitData, VerifyContributionData } from "../types/index"
44
46
  import { LogLevel } from "../types/enums"
45
- import { COMMON_ERRORS, logAndThrowError, makeError, printLog, SPECIFIC_ERRORS } from "../lib/errors"
47
+ import { COMMON_ERRORS, logAndThrowError, printLog, SPECIFIC_ERRORS } from "../lib/errors"
46
48
  import {
47
49
  createEC2Client,
48
50
  createSSMClient,
@@ -57,7 +59,6 @@ import {
57
59
  sleep,
58
60
  uploadFileToBucket
59
61
  } from "../lib/utils"
60
- import { EC2Client } from "@aws-sdk/client-ec2"
61
62
 
62
63
  dotenv.config()
63
64
 
@@ -214,57 +215,80 @@ const coordinate = async (
214
215
  * Wait until the command has completed its execution inside the VM.
215
216
  * @dev this method implements a custom interval to check 5 times after 1 minute if the command execution
216
217
  * has been completed or not by calling the `retrieveCommandStatus` method.
217
- * @param {any} resolve the promise.
218
- * @param {any} reject the promise.
219
218
  * @param {SSMClient} ssm the SSM client.
220
219
  * @param {string} vmInstanceId the unique identifier of the VM instance.
221
220
  * @param {string} commandId the unique identifier of the VM command.
222
221
  * @returns <Promise<void>> true when the command execution succeed; otherwise false.
223
222
  */
224
- const waitForVMCommandExecution = (
225
- resolve: any,
226
- reject: any,
227
- ssm: SSMClient,
228
- vmInstanceId: string,
229
- commandId: string
230
- ) => {
231
- const interval = setInterval(async () => {
232
- try {
233
- // Get command status.
234
- const cmdStatus = await retrieveCommandStatus(ssm, vmInstanceId, commandId)
235
- printLog(`Checking command ${commandId} status => ${cmdStatus}`, LogLevel.DEBUG)
236
-
237
- if (cmdStatus === CommandInvocationStatus.SUCCESS) {
238
- printLog(`Command ${commandId} successfully completed`, LogLevel.DEBUG)
239
-
240
- // Resolve the promise.
241
- resolve()
242
- } else if (cmdStatus === CommandInvocationStatus.FAILED) {
243
- logAndThrowError(SPECIFIC_ERRORS.SE_VM_FAILED_COMMAND_EXECUTION)
244
- reject()
245
- } else if (cmdStatus === CommandInvocationStatus.TIMED_OUT) {
246
- logAndThrowError(SPECIFIC_ERRORS.SE_VM_TIMEDOUT_COMMAND_EXECUTION)
247
- reject()
248
- } else if (cmdStatus === CommandInvocationStatus.CANCELLED) {
249
- logAndThrowError(SPECIFIC_ERRORS.SE_VM_CANCELLED_COMMAND_EXECUTION)
250
- reject()
251
- } else if (cmdStatus === CommandInvocationStatus.DELAYED) {
252
- logAndThrowError(SPECIFIC_ERRORS.SE_VM_DELAYED_COMMAND_EXECUTION)
253
- reject()
254
- }
255
- } catch (error: any) {
256
- printLog(`Invalid command ${commandId} execution`, LogLevel.DEBUG)
223
+ const waitForVMCommandExecution = (ssm: SSMClient, vmInstanceId: string, commandId: string): Promise<void> =>
224
+ new Promise((resolve, reject) => {
225
+ const poll = async () => {
226
+ try {
227
+ // Get command status.
228
+ const cmdStatus = await retrieveCommandStatus(ssm, vmInstanceId, commandId)
229
+ printLog(`Checking command ${commandId} status => ${cmdStatus}`, LogLevel.DEBUG)
230
+
231
+ let error: HttpsError | undefined
232
+ switch (cmdStatus) {
233
+ case CommandInvocationStatus.CANCELLING:
234
+ case CommandInvocationStatus.CANCELLED: {
235
+ error = SPECIFIC_ERRORS.SE_VM_CANCELLED_COMMAND_EXECUTION
236
+ break
237
+ }
238
+ case CommandInvocationStatus.DELAYED: {
239
+ error = SPECIFIC_ERRORS.SE_VM_DELAYED_COMMAND_EXECUTION
240
+ break
241
+ }
242
+ case CommandInvocationStatus.FAILED: {
243
+ error = SPECIFIC_ERRORS.SE_VM_FAILED_COMMAND_EXECUTION
244
+ break
245
+ }
246
+ case CommandInvocationStatus.TIMED_OUT: {
247
+ error = SPECIFIC_ERRORS.SE_VM_TIMEDOUT_COMMAND_EXECUTION
248
+ break
249
+ }
250
+ case CommandInvocationStatus.IN_PROGRESS:
251
+ case CommandInvocationStatus.PENDING: {
252
+ // wait a minute and poll again
253
+ setTimeout(poll, 60000)
254
+ return
255
+ }
256
+ case CommandInvocationStatus.SUCCESS: {
257
+ printLog(`Command ${commandId} successfully completed`, LogLevel.DEBUG)
258
+
259
+ // Resolve the promise.
260
+ resolve()
261
+ return
262
+ }
263
+ default: {
264
+ logAndThrowError(SPECIFIC_ERRORS.SE_VM_UNKNOWN_COMMAND_STATUS)
265
+ }
266
+ }
267
+
268
+ if (error) {
269
+ logAndThrowError(error)
270
+ }
271
+ } catch (error: any) {
272
+ printLog(`Invalid command ${commandId} execution`, LogLevel.DEBUG)
257
273
 
258
- if (!error.toString().includes(commandId)) logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION)
274
+ const ec2 = await createEC2Client()
259
275
 
260
- // Reject the promise.
261
- reject()
262
- } finally {
263
- // Clear the interval.
264
- clearInterval(interval)
276
+ // if it errors out, let's just log it as a warning so the coordinator is aware
277
+ try {
278
+ await stopEC2Instance(ec2, vmInstanceId)
279
+ } catch (error: any) {
280
+ printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${error}`, LogLevel.WARN)
281
+ }
282
+
283
+ if (!error.toString().includes(commandId)) logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION)
284
+
285
+ // Reject the promise.
286
+ reject()
287
+ }
265
288
  }
266
- }, 60000) // 1 minute.
267
- }
289
+
290
+ setTimeout(poll, 60000)
291
+ })
268
292
 
269
293
  /**
270
294
  * This method is used to coordinate the waiting queues of ceremony circuits.
@@ -286,7 +310,7 @@ const waitForVMCommandExecution = (
286
310
  * - Just completed a contribution or all contributions for each circuit. If yes, coordinate (multi-participant scenario).
287
311
  */
288
312
  export const coordinateCeremonyParticipant = functionsV1
289
- .region('europe-west1')
313
+ .region("europe-west1")
290
314
  .runWith({
291
315
  memory: "512MB"
292
316
  })
@@ -387,7 +411,6 @@ export const coordinateCeremonyParticipant = functionsV1
387
411
  }
388
412
  })
389
413
 
390
-
391
414
  /**
392
415
  * Recursive function to check whether an EC2 is in a running state
393
416
  * @notice required step to run commands
@@ -396,23 +419,18 @@ export const coordinateCeremonyParticipant = functionsV1
396
419
  * @param attempts <number> - how many times to retry before failing
397
420
  * @returns <Promise<boolean>> - whether the VM was started
398
421
  */
399
- const checkIfVMRunning = async (
400
- ec2: EC2Client,
401
- vmInstanceId: string,
402
- attempts = 5
403
- ): Promise<boolean> => {
422
+ const checkIfVMRunning = async (ec2: EC2Client, vmInstanceId: string, attempts = 5): Promise<boolean> => {
404
423
  // if we tried 5 times, then throw an error
405
424
  if (attempts <= 0) logAndThrowError(SPECIFIC_ERRORS.SE_VM_NOT_RUNNING)
406
425
 
407
- await sleep(60000); // Wait for 1 min
408
- const isVMRunning = await checkIfRunning(ec2, vmInstanceId)
426
+ await sleep(60000) // Wait for 1 min
427
+ const isVMRunning = await checkIfRunning(ec2, vmInstanceId)
409
428
 
410
429
  if (!isVMRunning) {
411
430
  printLog(`VM not running, ${attempts - 1} attempts remaining. Retrying in 1 minute...`, LogLevel.DEBUG)
412
- return await checkIfVMRunning(ec2, vmInstanceId, attempts - 1)
413
- } else {
414
- return true
431
+ return checkIfVMRunning(ec2, vmInstanceId, attempts - 1)
415
432
  }
433
+ return true
416
434
  }
417
435
 
418
436
  /**
@@ -442,7 +460,7 @@ const checkIfVMRunning = async (
442
460
  * 2) Send all updates atomically to the Firestore database.
443
461
  */
444
462
  export const verifycontribution = functionsV2.https.onCall(
445
- { memory: "16GiB", timeoutSeconds: 3600, region: 'europe-west1' },
463
+ { memory: "16GiB", timeoutSeconds: 3600, region: "europe-west1" },
446
464
  async (request: functionsV2.https.CallableRequest<VerifyContributionData>): Promise<any> => {
447
465
  if (!request.auth || (!request.auth.token.participant && !request.auth.token.coordinator))
448
466
  logAndThrowError(SPECIFIC_ERRORS.SE_AUTH_NO_CURRENT_AUTH_USER)
@@ -610,9 +628,6 @@ export const verifycontribution = functionsV2.https.onCall(
610
628
  verificationTranscriptTemporaryLocalPath,
611
629
  true
612
630
  )
613
-
614
- // Stop VM instance.
615
- await stopEC2Instance(ec2, vmInstanceId)
616
631
  } else {
617
632
  // Upload verification transcript.
618
633
  /// nb. do not use multi-part upload here due to small file size.
@@ -689,6 +704,17 @@ export const verifycontribution = functionsV2.https.onCall(
689
704
  })
690
705
  }
691
706
 
707
+ // Stop VM instance
708
+ if (isUsingVM) {
709
+ // using try and catch as the VM stopping function can throw
710
+ // however we want to continue without stopping as the
711
+ // verification was valid, and inform the coordinator
712
+ try {
713
+ await stopEC2Instance(ec2, vmInstanceId)
714
+ } catch (error: any) {
715
+ printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${error}`, LogLevel.WARN)
716
+ }
717
+ }
692
718
  // Step (1.A.4.C)
693
719
  if (!isFinalizing) {
694
720
  // Step (1.A.4.C.1)
@@ -708,7 +734,7 @@ export const verifycontribution = functionsV2.https.onCall(
708
734
  ? (avgVerifyCloudFunctionTime + verifyCloudFunctionTime) / 2
709
735
  : verifyCloudFunctionTime
710
736
 
711
- // Prepare tx to update circuit average contribution/verification time.
737
+ // Prepare tx to update circuit average contribution/verification time.
712
738
  const updatedCircuitDoc = await getDocumentById(getCircuitsCollectionPath(ceremonyId), circuitId)
713
739
  const { waitingQueue: updatedWaitingQueue } = updatedCircuitDoc.data()!
714
740
  /// @dev this must happen only for valid contributions.
@@ -782,9 +808,7 @@ export const verifycontribution = functionsV2.https.onCall(
782
808
  printLog(`Starting the execution of command ${commandId}`, LogLevel.DEBUG)
783
809
 
784
810
  // Step (1.A.3.3).
785
- return new Promise<void>((resolve, reject) =>
786
- waitForVMCommandExecution(resolve, reject, ssm, vmInstanceId, commandId)
787
- )
811
+ return waitForVMCommandExecution(ssm, vmInstanceId, commandId)
788
812
  .then(async () => {
789
813
  // Command execution successfully completed.
790
814
  printLog(`Command ${commandId} execution has been successfully completed`, LogLevel.DEBUG)
@@ -796,59 +820,57 @@ export const verifycontribution = functionsV2.https.onCall(
796
820
 
797
821
  logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION)
798
822
  })
799
- } else {
800
- // CF approach.
801
- printLog(`CF mechanism`, LogLevel.DEBUG)
823
+ }
802
824
 
803
- const potStoragePath = getPotStorageFilePath(files.potFilename)
804
- const firstZkeyStoragePath = getZkeyStorageFilePath(prefix, `${prefix}_${genesisZkeyIndex}.zkey`)
805
- // Prepare temporary file paths.
806
- // (nb. these are needed to download the necessary artifacts for verification from AWS S3).
807
- verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(
808
- verificationTranscriptCompleteFilename
809
- )
810
- const potTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.pot`)
811
- const firstZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_genesis.zkey`)
812
- const lastZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_last.zkey`)
813
-
814
- // Create and populate transcript.
815
- const transcriptLogger = createCustomLoggerForFile(verificationTranscriptTemporaryLocalPath)
816
- transcriptLogger.info(
817
- `${
818
- isFinalizing ? `Final verification` : `Verification`
819
- } transcript for ${prefix} circuit Phase 2 contribution.\n${
820
- isFinalizing ? `Coordinator ` : `Contributor # ${Number(lastZkeyIndex)}`
821
- } (${contributorOrCoordinatorIdentifier})\n`
822
- )
825
+ // CF approach.
826
+ printLog(`CF mechanism`, LogLevel.DEBUG)
827
+
828
+ const potStoragePath = getPotStorageFilePath(files.potFilename)
829
+ const firstZkeyStoragePath = getZkeyStorageFilePath(prefix, `${prefix}_${genesisZkeyIndex}.zkey`)
830
+ // Prepare temporary file paths.
831
+ // (nb. these are needed to download the necessary artifacts for verification from AWS S3).
832
+ verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(verificationTranscriptCompleteFilename)
833
+ const potTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.pot`)
834
+ const firstZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_genesis.zkey`)
835
+ const lastZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_last.zkey`)
836
+
837
+ // Create and populate transcript.
838
+ const transcriptLogger = createCustomLoggerForFile(verificationTranscriptTemporaryLocalPath)
839
+ transcriptLogger.info(
840
+ `${
841
+ isFinalizing ? `Final verification` : `Verification`
842
+ } transcript for ${prefix} circuit Phase 2 contribution.\n${
843
+ isFinalizing ? `Coordinator ` : `Contributor # ${Number(lastZkeyIndex)}`
844
+ } (${contributorOrCoordinatorIdentifier})\n`
845
+ )
823
846
 
824
- // Step (1.A.2).
825
- await downloadArtifactFromS3Bucket(bucketName, potStoragePath, potTempFilePath)
826
- await downloadArtifactFromS3Bucket(bucketName, firstZkeyStoragePath, firstZkeyTempFilePath)
827
- await downloadArtifactFromS3Bucket(bucketName, lastZkeyStoragePath, lastZkeyTempFilePath)
828
-
829
- // Step (1.A.4).
830
- isContributionValid = await zKey.verifyFromInit(
831
- firstZkeyTempFilePath,
832
- potTempFilePath,
833
- lastZkeyTempFilePath,
834
- transcriptLogger
835
- )
836
-
837
- // Compute contribution hash.
838
- lastZkeyBlake2bHash = await blake512FromPath(lastZkeyTempFilePath)
847
+ // Step (1.A.2).
848
+ await downloadArtifactFromS3Bucket(bucketName, potStoragePath, potTempFilePath)
849
+ await downloadArtifactFromS3Bucket(bucketName, firstZkeyStoragePath, firstZkeyTempFilePath)
850
+ await downloadArtifactFromS3Bucket(bucketName, lastZkeyStoragePath, lastZkeyTempFilePath)
839
851
 
840
- // Free resources by unlinking temporary folders.
841
- // Do not free-up verification transcript path here.
842
- try {
843
- fs.unlinkSync(potTempFilePath)
844
- fs.unlinkSync(firstZkeyTempFilePath)
845
- fs.unlinkSync(lastZkeyTempFilePath)
846
- } catch (error: any) {
847
- printLog(`Error while unlinking temporary files - Error ${error}`, LogLevel.WARN)
848
- }
852
+ // Step (1.A.4).
853
+ isContributionValid = await zKey.verifyFromInit(
854
+ firstZkeyTempFilePath,
855
+ potTempFilePath,
856
+ lastZkeyTempFilePath,
857
+ transcriptLogger
858
+ )
849
859
 
850
- await completeVerification()
860
+ // Compute contribution hash.
861
+ lastZkeyBlake2bHash = await blake512FromPath(lastZkeyTempFilePath)
862
+
863
+ // Free resources by unlinking temporary folders.
864
+ // Do not free-up verification transcript path here.
865
+ try {
866
+ fs.unlinkSync(potTempFilePath)
867
+ fs.unlinkSync(firstZkeyTempFilePath)
868
+ fs.unlinkSync(lastZkeyTempFilePath)
869
+ } catch (error: any) {
870
+ printLog(`Error while unlinking temporary files - Error ${error}`, LogLevel.WARN)
851
871
  }
872
+
873
+ await completeVerification()
852
874
  }
853
875
  }
854
876
  )
@@ -859,7 +881,7 @@ export const verifycontribution = functionsV2.https.onCall(
859
881
  * this does not happen if the participant is actually the coordinator who is finalizing the ceremony.
860
882
  */
861
883
  export const refreshParticipantAfterContributionVerification = functionsV1
862
- .region('europe-west1')
884
+ .region("europe-west1")
863
885
  .runWith({
864
886
  memory: "512MB"
865
887
  })
@@ -942,7 +964,7 @@ export const refreshParticipantAfterContributionVerification = functionsV1
942
964
  * and verification key extracted from the circuit final contribution (as part of the ceremony finalization process).
943
965
  */
944
966
  export const finalizeCircuit = functionsV1
945
- .region('europe-west1')
967
+ .region("europe-west1")
946
968
  .runWith({
947
969
  memory: "512MB"
948
970
  })
@@ -8,7 +8,7 @@ import {
8
8
  ParticipantContributionStep,
9
9
  getParticipantsCollectionPath,
10
10
  commonTerms
11
- } from "@p0tion/actions"
11
+ } from "@devtion/actions"
12
12
  import { FieldValue } from "firebase-admin/firestore"
13
13
  import {
14
14
  PermanentlyStoreCurrentContributionTimeAndHash,
@@ -44,7 +44,7 @@ dotenv.config()
44
44
  * @dev true when the participant can participate (1.A, 3.B, 1.D); otherwise false.
45
45
  */
46
46
  export const checkParticipantForCeremony = functions
47
- .region('europe-west1')
47
+ .region("europe-west1")
48
48
  .runWith({
49
49
  memory: "512MB"
50
50
  })
@@ -134,7 +134,7 @@ export const checkParticipantForCeremony = functions
134
134
  participantDoc.ref.update({
135
135
  status: ParticipantStatus.EXHUMED,
136
136
  contributions,
137
- tempContributionData: tempContributionData ? tempContributionData : FieldValue.delete(),
137
+ tempContributionData: tempContributionData || FieldValue.delete(),
138
138
  contributionStep: ParticipantContributionStep.DOWNLOADING,
139
139
  contributionStartedAt: 0,
140
140
  verificationStartedAt: FieldValue.delete(),
@@ -175,7 +175,7 @@ export const checkParticipantForCeremony = functions
175
175
  * 2) the participant has just finished the contribution for a circuit (contributionProgress != 0 && status = CONTRIBUTED && contributionStep = COMPLETED).
176
176
  */
177
177
  export const progressToNextCircuitForContribution = functions
178
- .region('europe-west1')
178
+ .region("europe-west1")
179
179
  .runWith({
180
180
  memory: "512MB"
181
181
  })
@@ -233,7 +233,7 @@ export const progressToNextCircuitForContribution = functions
233
233
  * 5) Completed contribution computation and verification.
234
234
  */
235
235
  export const progressToNextContributionStep = functions
236
- .region('europe-west1')
236
+ .region("europe-west1")
237
237
  .runWith({
238
238
  memory: "512MB"
239
239
  })
@@ -296,7 +296,7 @@ export const progressToNextContributionStep = functions
296
296
  * @dev enable the current contributor to resume a contribution from where it had left off.
297
297
  */
298
298
  export const permanentlyStoreCurrentContributionTimeAndHash = functions
299
- .region('europe-west1')
299
+ .region("europe-west1")
300
300
  .runWith({
301
301
  memory: "512MB"
302
302
  })
@@ -355,7 +355,7 @@ export const permanentlyStoreCurrentContributionTimeAndHash = functions
355
355
  * @dev enable the current contributor to resume a multi-part upload from where it had left off.
356
356
  */
357
357
  export const temporaryStoreCurrentContributionMultiPartUploadId = functions
358
- .region('europe-west1')
358
+ .region("europe-west1")
359
359
  .runWith({
360
360
  memory: "512MB"
361
361
  })
@@ -409,7 +409,7 @@ export const temporaryStoreCurrentContributionMultiPartUploadId = functions
409
409
  * @dev enable the current contributor to resume a multi-part upload from where it had left off.
410
410
  */
411
411
  export const temporaryStoreCurrentContributionUploadedChunkData = functions
412
- .region('europe-west1')
412
+ .region("europe-west1")
413
413
  .runWith({
414
414
  memory: "512MB"
415
415
  })
@@ -469,7 +469,7 @@ export const temporaryStoreCurrentContributionUploadedChunkData = functions
469
469
  * contributed to every selected ceremony circuits (= DONE).
470
470
  */
471
471
  export const checkAndPrepareCoordinatorForFinalization = functions
472
- .region('europe-west1')
472
+ .region("europe-west1")
473
473
  .runWith({
474
474
  memory: "512MB"
475
475
  })
@@ -20,7 +20,7 @@ import {
20
20
  ParticipantContributionStep,
21
21
  formatZkeyIndex,
22
22
  getZkeyStorageFilePath
23
- } from "@p0tion/actions"
23
+ } from "@devtion/actions"
24
24
  import { getCeremonyCircuits, getDocumentById } from "../lib/utils"
25
25
  import { COMMON_ERRORS, logAndThrowError, makeError, printLog, SPECIFIC_ERRORS } from "../lib/errors"
26
26
  import { LogLevel } from "../types/enums"
@@ -193,8 +193,10 @@ export const createBucket = functions
193
193
  CORSConfiguration: {
194
194
  CORSRules: [
195
195
  {
196
- AllowedMethods: ["GET"],
197
- AllowedOrigins: ["*"]
196
+ AllowedMethods: ["GET", "PUT"],
197
+ AllowedOrigins: ["*"],
198
+ ExposeHeaders: ["ETag", "Content-Length"],
199
+ AllowedHeaders: ["*"]
198
200
  }
199
201
  ]
200
202
  }
@@ -407,7 +409,8 @@ export const startMultiPartUpload = functions
407
409
  export const generatePreSignedUrlsParts = functions
408
410
  .region("europe-west1")
409
411
  .runWith({
410
- memory: "512MB"
412
+ memory: "512MB",
413
+ timeoutSeconds: 300
411
414
  })
412
415
  .https.onCall(
413
416
  async (
@@ -9,7 +9,7 @@ import {
9
9
  ParticipantStatus,
10
10
  getTimeoutsCollectionPath,
11
11
  commonTerms
12
- } from "@p0tion/actions"
12
+ } from "@devtion/actions"
13
13
  import {
14
14
  getCeremonyCircuits,
15
15
  getCurrentServerTimestampInMillis,
@@ -64,7 +64,7 @@ export const checkAndRemoveBlockingContributor = functions
64
64
  const circuits = await getCeremonyCircuits(ceremony.id)
65
65
 
66
66
  // Extract ceremony data.
67
- const { timeoutMechanismType, penalty } = ceremony.data()!
67
+ const { timeoutType: timeoutMechanismType, penalty } = ceremony.data()!
68
68
 
69
69
  for (const circuit of circuits) {
70
70
  if (!circuit.data())
@@ -281,7 +281,8 @@ export const resumeContributionAfterTimeoutExpiration = functions
281
281
  if (status === ParticipantStatus.EXHUMED)
282
282
  await participantDoc.ref.update({
283
283
  status: ParticipantStatus.READY,
284
- lastUpdated: getCurrentServerTimestampInMillis()
284
+ lastUpdated: getCurrentServerTimestampInMillis(),
285
+ tempContributionData: {}
285
286
  })
286
287
  else logAndThrowError(SPECIFIC_ERRORS.SE_CONTRIBUTE_CANNOT_PROGRESS_TO_NEXT_CIRCUIT)
287
288
 
@@ -2,7 +2,7 @@ import * as functions from "firebase-functions"
2
2
  import { UserRecord } from "firebase-functions/v1/auth"
3
3
  import admin from "firebase-admin"
4
4
  import dotenv from "dotenv"
5
- import { commonTerms, githubReputation } from "@p0tion/actions"
5
+ import { commonTerms, githubReputation } from "@devtion/actions"
6
6
  import { encode } from "html-entities"
7
7
  import { getGitHubVariables, getCurrentServerTimestampInMillis } from "../lib/utils"
8
8
  import { logAndThrowError, makeError, printLog, SPECIFIC_ERRORS } from "../lib/errors"
@@ -40,8 +40,12 @@ export const registerAuthUser = functions
40
40
  const { uid } = user
41
41
  // Reference to a document using uid.
42
42
  const userRef = firestore.collection(commonTerms.collections.users.name).doc(uid)
43
- // html encode the display name
44
- const encodedDisplayName = encode(displayName)
43
+ // html encode the display name (or put the ID if the name is not displayed)
44
+ const encodedDisplayName =
45
+ user.displayName === "Null" || user.displayName === null ? user.uid : encode(displayName)
46
+
47
+ // store the avatar URL of a contributor
48
+ let avatarUrl: string = ""
45
49
  // we only do reputation check if the user is not a coordinator
46
50
  if (
47
51
  !(
@@ -56,13 +60,14 @@ export const registerAuthUser = functions
56
60
 
57
61
  // this return true or false
58
62
  try {
59
- const res = await githubReputation(
63
+ const { reputable, avatarUrl: avatarURL } = await githubReputation(
60
64
  user.providerData[0].uid,
61
65
  vars.minimumFollowing,
62
66
  vars.minimumFollowers,
63
- vars.minimumPublicRepos
67
+ vars.minimumPublicRepos,
68
+ vars.minimumAge
64
69
  )
65
- if (!res) {
70
+ if (!reputable) {
66
71
  // Delete user
67
72
  await auth.deleteUser(user.uid)
68
73
  // Throw error
@@ -70,11 +75,22 @@ export const registerAuthUser = functions
70
75
  makeError(
71
76
  "permission-denied",
72
77
  "The user is not allowed to sign up because their Github reputation is not high enough.",
73
- `The user ${user.displayName} is not allowed to sign up because their Github reputation is not high enough. Please contact the administrator if you think this is a mistake.`
78
+ `The user ${
79
+ user.displayName === "Null" || user.displayName === null
80
+ ? user.uid
81
+ : user.displayName
82
+ } is not allowed to sign up because their Github reputation is not high enough. Please contact the administrator if you think this is a mistake.`
74
83
  )
75
84
  )
76
85
  }
77
- printLog(`Github reputation check passed for user ${user.displayName}`, LogLevel.DEBUG)
86
+ // store locally
87
+ avatarUrl = avatarURL
88
+ printLog(
89
+ `Github reputation check passed for user ${
90
+ user.displayName === "Null" || user.displayName === null ? user.uid : user.displayName
91
+ }`,
92
+ LogLevel.DEBUG
93
+ )
78
94
  } catch (error: any) {
79
95
  // Delete user
80
96
  await auth.deleteUser(user.uid)
@@ -89,6 +105,8 @@ export const registerAuthUser = functions
89
105
  }
90
106
  }
91
107
  // Set document (nb. we refer to providerData[0] because we use Github OAuth provider only).
108
+ // In future releases we might want to loop through the providerData array as we support
109
+ // more providers.
92
110
  await userRef.set({
93
111
  name: encodedDisplayName,
94
112
  encodedDisplayName,
@@ -101,7 +119,14 @@ export const registerAuthUser = functions
101
119
  photoURL: photoURL || "",
102
120
  lastUpdated: getCurrentServerTimestampInMillis()
103
121
  })
122
+
123
+ // we want to create a new collection for the users to store the avatars
124
+ const avatarRef = firestore.collection(commonTerms.collections.avatars.name).doc(uid)
125
+ await avatarRef.set({
126
+ avatarUrl: avatarUrl || ""
127
+ })
104
128
  printLog(`Authenticated user document with identifier ${uid} has been correctly stored`, LogLevel.DEBUG)
129
+ printLog(`Authenticated user avatar with identifier ${uid} has been correctly stored`, LogLevel.DEBUG)
105
130
  })
106
131
  /**
107
132
  * Set custom claims for role-based access control on the newly created user.