@devtion/backend 0.0.0-0fd4368 → 0.0.0-142ec0a

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.
@@ -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())
@@ -174,7 +174,7 @@ export const checkAndRemoveBlockingContributor = functions
174
174
  const batch = firestore.batch()
175
175
 
176
176
  // Remove current contributor from waiting queue.
177
- contributors.shift(1)
177
+ contributors.shift()
178
178
 
179
179
  // Check if someone else is ready to start the contribution.
180
180
  if (contributors.length > 0) {
@@ -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.
package/src/lib/errors.ts CHANGED
@@ -184,6 +184,11 @@ export const SPECIFIC_ERRORS = {
184
184
  "unavailable",
185
185
  "VM command execution has been delayed since there were no available instance at the moment",
186
186
  "Please, contact the coordinator if this error persists."
187
+ ),
188
+ SE_VM_UNKNOWN_COMMAND_STATUS: makeError(
189
+ "unavailable",
190
+ "VM command execution has failed due to an unknown status code",
191
+ "Please, contact the coordinator if this error persists."
187
192
  )
188
193
  }
189
194
 
package/src/lib/utils.ts CHANGED
@@ -10,7 +10,7 @@ import admin from "firebase-admin"
10
10
  import dotenv from "dotenv"
11
11
  import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3"
12
12
  import { getSignedUrl } from "@aws-sdk/s3-request-presigner"
13
- import { createWriteStream, fstat } from "node:fs"
13
+ import { createWriteStream } from "node:fs"
14
14
  import { pipeline } from "node:stream"
15
15
  import { promisify } from "node:util"
16
16
  import { readFileSync } from "fs"
@@ -25,7 +25,7 @@ import {
25
25
  CeremonyState,
26
26
  finalContributionIndex,
27
27
  CircuitDocument
28
- } from "@p0tion/actions"
28
+ } from "@devtion/actions"
29
29
  import fetch from "@adobe/node-fetch-retry"
30
30
  import path from "path"
31
31
  import os from "os"
@@ -166,7 +166,7 @@ export const getCircuitDocumentByPosition = async (
166
166
  // Query for all ceremony circuits.
167
167
  const circuits = await getCeremonyCircuits(ceremonyId)
168
168
 
169
- // Apply a filter using the sequence postion.
169
+ // Apply a filter using the sequence position.
170
170
  const matchedCircuits = circuits.filter(
171
171
  (circuit: DocumentData) => circuit.data().sequencePosition === sequencePosition
172
172
  )
@@ -217,7 +217,7 @@ export const downloadArtifactFromS3Bucket = async (bucketName: string, objectKey
217
217
  const streamPipeline = promisify(pipeline)
218
218
  await streamPipeline(response.body, writeStream)
219
219
 
220
- writeStream.on('finish', () => {
220
+ writeStream.on("finish", () => {
221
221
  writeStream.end()
222
222
  })
223
223
  }
@@ -305,7 +305,7 @@ export const deleteObject = async (bucketName: string, objectKey: string) => {
305
305
 
306
306
  // Prepare command.
307
307
  const command = new DeleteObjectCommand({ Bucket: bucketName, Key: objectKey })
308
-
308
+
309
309
  // Execute command.
310
310
  const data = await client.send(command)
311
311
 
@@ -385,14 +385,16 @@ export const getGitHubVariables = (): any => {
385
385
  if (
386
386
  !process.env.GITHUB_MINIMUM_FOLLOWERS ||
387
387
  !process.env.GITHUB_MINIMUM_FOLLOWING ||
388
- !process.env.GITHUB_MINIMUM_PUBLIC_REPOS
388
+ !process.env.GITHUB_MINIMUM_PUBLIC_REPOS ||
389
+ !process.env.GITHUB_MINIMUM_AGE
389
390
  )
390
391
  logAndThrowError(COMMON_ERRORS.CM_WRONG_CONFIGURATION)
391
392
 
392
393
  return {
393
394
  minimumFollowers: Number(process.env.GITHUB_MINIMUM_FOLLOWERS),
394
395
  minimumFollowing: Number(process.env.GITHUB_MINIMUM_FOLLOWING),
395
- minimumPublicRepos: Number(process.env.GITHUB_MINIMUM_PUBLIC_REPOS)
396
+ minimumPublicRepos: Number(process.env.GITHUB_MINIMUM_PUBLIC_REPOS),
397
+ minimumAge: Number(process.env.GITHUB_MINIMUM_AGE)
396
398
  }
397
399
  }
398
400
 
@@ -404,7 +406,7 @@ export const getAWSVariables = (): any => {
404
406
  if (
405
407
  !process.env.AWS_ACCESS_KEY_ID ||
406
408
  !process.env.AWS_SECRET_ACCESS_KEY ||
407
- !process.env.AWS_ROLE_ARN ||
409
+ !process.env.AWS_INSTANCE_PROFILE_ARN ||
408
410
  !process.env.AWS_AMI_ID ||
409
411
  !process.env.AWS_SNS_TOPIC_ARN
410
412
  )
@@ -414,7 +416,7 @@ export const getAWSVariables = (): any => {
414
416
  accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
415
417
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
416
418
  region: process.env.AWS_REGION || "eu-central-1",
417
- roleArn: process.env.AWS_ROLE_ARN!,
419
+ instanceProfileArn: process.env.AWS_INSTANCE_PROFILE_ARN!,
418
420
  amiId: process.env.AWS_AMI_ID!,
419
421
  snsTopic: process.env.AWS_SNS_TOPIC_ARN!
420
422
  }
@@ -1,4 +1,4 @@
1
- import { CeremonyInputData, CircuitDocument, ETagWithPartNumber } from "@p0tion/actions"
1
+ import { CeremonyInputData, CircuitDocument, ETagWithPartNumber } from "@devtion/actions"
2
2
 
3
3
  /**
4
4
  * Group all the necessary data needed for running the `setupCeremony` cloud function.