@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.
- package/README.md +28 -2
- package/dist/src/functions/index.js +157 -165
- package/dist/src/functions/index.mjs +157 -165
- package/dist/types/functions/ceremony.d.ts.map +1 -1
- package/dist/types/functions/circuit.d.ts.map +1 -1
- package/dist/types/functions/storage.d.ts.map +1 -1
- package/dist/types/functions/timeout.d.ts.map +1 -1
- package/dist/types/functions/user.d.ts.map +1 -1
- package/dist/types/lib/errors.d.ts +1 -0
- package/dist/types/lib/errors.d.ts.map +1 -1
- package/dist/types/lib/utils.d.ts +1 -1
- package/dist/types/lib/utils.d.ts.map +1 -1
- package/dist/types/types/index.d.ts +1 -1
- package/package.json +3 -3
- package/src/functions/ceremony.ts +9 -4
- package/src/functions/circuit.ts +137 -185
- package/src/functions/participant.ts +9 -9
- package/src/functions/storage.ts +7 -4
- package/src/functions/timeout.ts +5 -4
- package/src/functions/user.ts +33 -8
- package/src/lib/errors.ts +5 -0
- package/src/lib/utils.ts +11 -9
- package/src/types/index.ts +1 -1
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
ParticipantContributionStep,
|
|
9
9
|
getParticipantsCollectionPath,
|
|
10
10
|
commonTerms
|
|
11
|
-
} from "@
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
472
|
+
.region("europe-west1")
|
|
473
473
|
.runWith({
|
|
474
474
|
memory: "512MB"
|
|
475
475
|
})
|
package/src/functions/storage.ts
CHANGED
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
ParticipantContributionStep,
|
|
21
21
|
formatZkeyIndex,
|
|
22
22
|
getZkeyStorageFilePath
|
|
23
|
-
} from "@
|
|
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 (
|
package/src/functions/timeout.ts
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
ParticipantStatus,
|
|
10
10
|
getTimeoutsCollectionPath,
|
|
11
11
|
commonTerms
|
|
12
|
-
} from "@
|
|
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(
|
|
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
|
|
package/src/functions/user.ts
CHANGED
|
@@ -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 "@
|
|
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 =
|
|
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
|
|
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 (!
|
|
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 ${
|
|
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
|
-
|
|
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
|
|
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 "@
|
|
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
|
|
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(
|
|
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.
|
|
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
|
-
|
|
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
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CeremonyInputData, CircuitDocument, ETagWithPartNumber } from "@
|
|
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.
|