@devtion/backend 0.0.0-92056fa → 0.0.0-9239207

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 (36) hide show
  1. package/README.md +7 -7
  2. package/dist/src/functions/index.js +626 -337
  3. package/dist/src/functions/index.mjs +629 -342
  4. package/dist/types/functions/bandada.d.ts +4 -0
  5. package/dist/types/functions/bandada.d.ts.map +1 -0
  6. package/dist/types/functions/ceremony.d.ts.map +1 -1
  7. package/dist/types/functions/circuit.d.ts.map +1 -1
  8. package/dist/types/functions/index.d.ts +2 -0
  9. package/dist/types/functions/index.d.ts.map +1 -1
  10. package/dist/types/functions/siwe.d.ts +4 -0
  11. package/dist/types/functions/siwe.d.ts.map +1 -0
  12. package/dist/types/functions/storage.d.ts.map +1 -1
  13. package/dist/types/functions/timeout.d.ts.map +1 -1
  14. package/dist/types/functions/user.d.ts.map +1 -1
  15. package/dist/types/lib/errors.d.ts +2 -1
  16. package/dist/types/lib/errors.d.ts.map +1 -1
  17. package/dist/types/lib/services.d.ts +7 -0
  18. package/dist/types/lib/services.d.ts.map +1 -1
  19. package/dist/types/lib/utils.d.ts.map +1 -1
  20. package/dist/types/types/index.d.ts +56 -0
  21. package/dist/types/types/index.d.ts.map +1 -1
  22. package/package.json +4 -3
  23. package/src/functions/bandada.ts +155 -0
  24. package/src/functions/ceremony.ts +12 -7
  25. package/src/functions/circuit.ts +408 -382
  26. package/src/functions/index.ts +2 -0
  27. package/src/functions/participant.ts +15 -15
  28. package/src/functions/siwe.ts +77 -0
  29. package/src/functions/storage.ts +11 -8
  30. package/src/functions/timeout.ts +7 -5
  31. package/src/functions/user.ts +22 -12
  32. package/src/lib/errors.ts +6 -1
  33. package/src/lib/services.ts +36 -0
  34. package/src/lib/utils.ts +10 -8
  35. package/src/types/declarations.d.ts +1 -0
  36. package/src/types/index.ts +60 -0
@@ -31,6 +31,8 @@ export {
31
31
  generatePreSignedUrlsParts,
32
32
  completeMultiPartUpload
33
33
  } from "./storage"
34
+ export { bandadaValidateProof } from "./bandada"
35
+ export { checkNonceOfSIWEAddress } from "./siwe"
34
36
  export { checkAndRemoveBlockingContributor, resumeContributionAfterTimeoutExpiration } from "./timeout"
35
37
 
36
38
  admin.initializeApp()
@@ -44,9 +44,9 @@ 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
- memory: "512MB"
49
+ memory: "1GB"
50
50
  })
51
51
  .https.onCall(async (data: { ceremonyId: string }, context: functions.https.CallableContext) => {
52
52
  if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
@@ -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,9 +175,9 @@ 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
- memory: "512MB"
180
+ memory: "1GB"
181
181
  })
182
182
  .https.onCall(async (data: { ceremonyId: string }, context: functions.https.CallableContext): Promise<void> => {
183
183
  if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
@@ -233,9 +233,9 @@ 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
- memory: "512MB"
238
+ memory: "1GB"
239
239
  })
240
240
  .https.onCall(async (data: { ceremonyId: string }, context: functions.https.CallableContext) => {
241
241
  if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
@@ -296,9 +296,9 @@ 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
- memory: "512MB"
301
+ memory: "1GB"
302
302
  })
303
303
  .https.onCall(
304
304
  async (data: PermanentlyStoreCurrentContributionTimeAndHash, context: functions.https.CallableContext) => {
@@ -355,9 +355,9 @@ 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
- memory: "512MB"
360
+ memory: "1GB"
361
361
  })
362
362
  .https.onCall(
363
363
  async (data: TemporaryStoreCurrentContributionMultiPartUploadId, context: functions.https.CallableContext) => {
@@ -409,9 +409,9 @@ 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
- memory: "512MB"
414
+ memory: "1GB"
415
415
  })
416
416
  .https.onCall(
417
417
  async (data: TemporaryStoreCurrentContributionUploadedChunkData, context: functions.https.CallableContext) => {
@@ -469,9 +469,9 @@ 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
- memory: "512MB"
474
+ memory: "1GB"
475
475
  })
476
476
  .https.onCall(async (data: { ceremonyId: string }, context: functions.https.CallableContext): Promise<boolean> => {
477
477
  if (!context.auth || !context.auth.token.coordinator) logAndThrowError(COMMON_ERRORS.CM_NOT_COORDINATOR_ROLE)
@@ -0,0 +1,77 @@
1
+ import dotenv from "dotenv"
2
+ import fetch from "@adobe/node-fetch-retry"
3
+ import * as functions from "firebase-functions"
4
+ import { getAuth } from "firebase-admin/auth"
5
+ import admin from "firebase-admin"
6
+ import { Auth0UserInfo, CheckNonceOfSIWEAddressRequest, CheckNonceOfSIWEAddressResponse } from "../types"
7
+ import { setEthProvider } from "../lib/services"
8
+
9
+ dotenv.config()
10
+
11
+ export const checkNonceOfSIWEAddress = functions
12
+ .region("europe-west1")
13
+ .runWith({ memory: "1GB" })
14
+ .https.onCall(async (data: CheckNonceOfSIWEAddressRequest): Promise<CheckNonceOfSIWEAddressResponse> => {
15
+ try {
16
+ const { auth0Token } = data
17
+ const result = (await fetch(`${process.env.AUTH0_APPLICATION_URL}/userinfo`, {
18
+ method: "GET",
19
+ headers: {
20
+ "content-type": "application/json",
21
+ authorization: `Bearer ${auth0Token}`
22
+ }
23
+ }).then((_res) => _res.json())) as Auth0UserInfo
24
+ if (!result.sub) {
25
+ return {
26
+ valid: false,
27
+ message: "No user detected. Please check device flow token"
28
+ }
29
+ }
30
+ const auth = getAuth()
31
+ // check nonce
32
+ const parts = result.sub.split("|")
33
+ const address = decodeURIComponent(parts[2]).split(":")[2]
34
+
35
+ const minimumNonce = Number(process.env.ETH_MINIMUM_NONCE)
36
+ const nonceBlockHeight = "latest" // process.env.ETH_NONCE_BLOCK_HEIGHT
37
+ // look up nonce for address @block
38
+ let nonceOk = true
39
+ if (minimumNonce > 0) {
40
+ const provider = setEthProvider()
41
+ console.log(`got provider - block # ${await provider.getBlockNumber()}`)
42
+ const nonce = await provider.getTransactionCount(address, nonceBlockHeight)
43
+ console.log(`nonce ${nonce}`)
44
+ nonceOk = nonce >= minimumNonce
45
+ }
46
+ console.log(`checking nonce ${nonceOk}`)
47
+ if (!nonceOk) {
48
+ return {
49
+ valid: false,
50
+ message: "Eth address does not meet the nonce requirements"
51
+ }
52
+ }
53
+ try {
54
+ await admin.auth().createUser({
55
+ displayName: address,
56
+ uid: address
57
+ })
58
+ } catch (error: any) {
59
+ // if user already exist then just pass
60
+ if (error.code !== "auth/uid-already-exists") {
61
+ throw new Error(error)
62
+ }
63
+ }
64
+ const token = await auth.createCustomToken(address)
65
+ return {
66
+ valid: true,
67
+ token
68
+ }
69
+ } catch (error) {
70
+ return {
71
+ valid: false,
72
+ message: `Something went wrong ${error}`
73
+ }
74
+ }
75
+ })
76
+
77
+ export default checkNonceOfSIWEAddress
@@ -134,7 +134,7 @@ const checkIfBucketIsDedicatedToCeremony = async (bucketName: string) => {
134
134
  export const createBucket = functions
135
135
  .region("europe-west1")
136
136
  .runWith({
137
- memory: "512MB"
137
+ memory: "1GB"
138
138
  })
139
139
  .https.onCall(async (data: CreateBucketData, context: functions.https.CallableContext) => {
140
140
  // Check if the user has the coordinator claim.
@@ -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
  }
@@ -236,7 +238,7 @@ export const createBucket = functions
236
238
  export const checkIfObjectExist = functions
237
239
  .region("europe-west1")
238
240
  .runWith({
239
- memory: "512MB"
241
+ memory: "1GB"
240
242
  })
241
243
  .https.onCall(async (data: BucketAndObjectKeyData, context: functions.https.CallableContext): Promise<boolean> => {
242
244
  // Check if the user has the coordinator claim.
@@ -292,7 +294,7 @@ export const checkIfObjectExist = functions
292
294
  export const generateGetObjectPreSignedUrl = functions
293
295
  .region("europe-west1")
294
296
  .runWith({
295
- memory: "512MB"
297
+ memory: "1GB"
296
298
  })
297
299
  .https.onCall(async (data: BucketAndObjectKeyData, context: functions.https.CallableContext): Promise<any> => {
298
300
  if (!context.auth) logAndThrowError(COMMON_ERRORS.CM_NOT_AUTHENTICATED)
@@ -339,7 +341,7 @@ export const generateGetObjectPreSignedUrl = functions
339
341
  export const startMultiPartUpload = functions
340
342
  .region("europe-west1")
341
343
  .runWith({
342
- memory: "512MB"
344
+ memory: "2GB"
343
345
  })
344
346
  .https.onCall(async (data: StartMultiPartUploadData, context: functions.https.CallableContext): Promise<any> => {
345
347
  if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
@@ -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: "1GB",
413
+ timeoutSeconds: 300
411
414
  })
412
415
  .https.onCall(
413
416
  async (
@@ -484,7 +487,7 @@ export const generatePreSignedUrlsParts = functions
484
487
  export const completeMultiPartUpload = functions
485
488
  .region("europe-west1")
486
489
  .runWith({
487
- memory: "512MB"
490
+ memory: "2GB"
488
491
  })
489
492
  .https.onCall(async (data: CompleteMultiPartUploadData, context: functions.https.CallableContext): Promise<any> => {
490
493
  if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
@@ -42,7 +42,7 @@ dotenv.config()
42
42
  export const checkAndRemoveBlockingContributor = functions
43
43
  .region("europe-west1")
44
44
  .runWith({
45
- memory: "512MB"
45
+ memory: "1GB"
46
46
  })
47
47
  .pubsub.schedule("every 1 minutes")
48
48
  .onRun(async () => {
@@ -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())
@@ -144,7 +144,8 @@ export const checkAndRemoveBlockingContributor = functions
144
144
  timeoutExpirationDateInMsForBlockingContributor < currentServerTimestamp &&
145
145
  (contributionStep === ParticipantContributionStep.DOWNLOADING ||
146
146
  contributionStep === ParticipantContributionStep.COMPUTING ||
147
- contributionStep === ParticipantContributionStep.UPLOADING)
147
+ contributionStep === ParticipantContributionStep.UPLOADING ||
148
+ contributionStep === ParticipantContributionStep.COMPLETED)
148
149
  )
149
150
  timeoutType = TimeoutType.BLOCKING_CONTRIBUTION
150
151
 
@@ -253,7 +254,7 @@ export const checkAndRemoveBlockingContributor = functions
253
254
  export const resumeContributionAfterTimeoutExpiration = functions
254
255
  .region("europe-west1")
255
256
  .runWith({
256
- memory: "512MB"
257
+ memory: "1GB"
257
258
  })
258
259
  .https.onCall(async (data: { ceremonyId: string }, context: functions.https.CallableContext): Promise<void> => {
259
260
  if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
@@ -281,7 +282,8 @@ export const resumeContributionAfterTimeoutExpiration = functions
281
282
  if (status === ParticipantStatus.EXHUMED)
282
283
  await participantDoc.ref.update({
283
284
  status: ParticipantStatus.READY,
284
- lastUpdated: getCurrentServerTimestampInMillis()
285
+ lastUpdated: getCurrentServerTimestampInMillis(),
286
+ tempContributionData: {}
285
287
  })
286
288
  else logAndThrowError(SPECIFIC_ERRORS.SE_CONTRIBUTE_CANNOT_PROGRESS_TO_NEXT_CIRCUIT)
287
289
 
@@ -18,7 +18,7 @@ dotenv.config()
18
18
  export const registerAuthUser = functions
19
19
  .region("europe-west1")
20
20
  .runWith({
21
- memory: "512MB"
21
+ memory: "1GB"
22
22
  })
23
23
  .auth.user()
24
24
  .onCreate(async (user: UserRecord) => {
@@ -41,7 +41,8 @@ export const registerAuthUser = functions
41
41
  // Reference to a document using uid.
42
42
  const userRef = firestore.collection(commonTerms.collections.users.name).doc(uid)
43
43
  // html encode the display name (or put the ID if the name is not displayed)
44
- const encodedDisplayName = user.displayName === "Null" || user.displayName === null ? user.uid : encode(displayName)
44
+ const encodedDisplayName =
45
+ user.displayName === "Null" || user.displayName === null ? user.uid : encode(displayName)
45
46
 
46
47
  // store the avatar URL of a contributor
47
48
  let avatarUrl: string = ""
@@ -54,7 +55,7 @@ export const registerAuthUser = functions
54
55
  ) {
55
56
  const auth = admin.auth()
56
57
  // if provider == github.com let's use our functions to check the user's reputation
57
- if (user.providerData[0].providerId === "github.com") {
58
+ if (user.providerData.length > 0 && user.providerData[0].providerId === "github.com") {
58
59
  const vars = getGitHubVariables()
59
60
 
60
61
  // this return true or false
@@ -63,7 +64,8 @@ export const registerAuthUser = functions
63
64
  user.providerData[0].uid,
64
65
  vars.minimumFollowing,
65
66
  vars.minimumFollowers,
66
- vars.minimumPublicRepos
67
+ vars.minimumPublicRepos,
68
+ vars.minimumAge
67
69
  )
68
70
  if (!reputable) {
69
71
  // Delete user
@@ -73,13 +75,22 @@ export const registerAuthUser = functions
73
75
  makeError(
74
76
  "permission-denied",
75
77
  "The user is not allowed to sign up because their Github reputation is not high enough.",
76
- `The user ${user.displayName === "Null" || user.displayName === null ? user.uid : 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.`
77
83
  )
78
84
  )
79
- }
85
+ }
80
86
  // store locally
81
87
  avatarUrl = avatarURL
82
- printLog(`Github reputation check passed for user ${user.displayName === "Null" || user.displayName === null ? user.uid : user.displayName }`, LogLevel.DEBUG)
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
+ )
83
94
  } catch (error: any) {
84
95
  // Delete user
85
96
  await auth.deleteUser(user.uid)
@@ -95,13 +106,13 @@ export const registerAuthUser = functions
95
106
  }
96
107
  // Set document (nb. we refer to providerData[0] because we use Github OAuth provider only).
97
108
  // In future releases we might want to loop through the providerData array as we support
98
- // more providers.
109
+ // more providers.
99
110
  await userRef.set({
100
111
  name: encodedDisplayName,
101
112
  encodedDisplayName,
102
113
  // Metadata.
103
114
  creationTime,
104
- lastSignInTime,
115
+ lastSignInTime: lastSignInTime || creationTime,
105
116
  // Optional.
106
117
  email: email || "",
107
118
  emailVerified: emailVerified || false,
@@ -112,9 +123,8 @@ export const registerAuthUser = functions
112
123
  // we want to create a new collection for the users to store the avatars
113
124
  const avatarRef = firestore.collection(commonTerms.collections.avatars.name).doc(uid)
114
125
  await avatarRef.set({
115
- avatarUrl: avatarUrl || "",
126
+ avatarUrl: avatarUrl || ""
116
127
  })
117
-
118
128
  printLog(`Authenticated user document with identifier ${uid} has been correctly stored`, LogLevel.DEBUG)
119
129
  printLog(`Authenticated user avatar with identifier ${uid} has been correctly stored`, LogLevel.DEBUG)
120
130
  })
@@ -126,7 +136,7 @@ export const registerAuthUser = functions
126
136
  export const processSignUpWithCustomClaims = functions
127
137
  .region("europe-west1")
128
138
  .runWith({
129
- memory: "512MB"
139
+ memory: "1GB"
130
140
  })
131
141
  .auth.user()
132
142
  .onCreate(async (user: UserRecord) => {
package/src/lib/errors.ts CHANGED
@@ -7,7 +7,7 @@ import { LogLevel } from "../types/enums"
7
7
  * @notice the set of Firebase Functions status codes. The codes are the same at the
8
8
  * ones exposed by {@link https://github.com/grpc/grpc/blob/master/doc/statuscodes.md | gRPC}.
9
9
  * @param errorCode <FunctionsErrorCode> - the set of possible error codes.
10
- * @param message <string> - the error messge.
10
+ * @param message <string> - the error message.
11
11
  * @param [details] <string> - the details of the error (optional).
12
12
  * @returns <HttpsError>
13
13
  */
@@ -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
 
@@ -1,6 +1,11 @@
1
+ import dotenv from "dotenv"
2
+ import ethers from "ethers"
1
3
  import { S3Client } from "@aws-sdk/client-s3"
2
4
  import { COMMON_ERRORS, logAndThrowError } from "./errors"
3
5
 
6
+ dotenv.config()
7
+ let provider: ethers.providers.Provider
8
+
4
9
  /**
5
10
  * Return a configured and connected instance of the AWS S3 client.
6
11
  * @dev this method check and utilize the environment variables to configure the connection
@@ -26,3 +31,34 @@ export const getS3Client = async (): Promise<S3Client> => {
26
31
  region: process.env.AWS_REGION!
27
32
  })
28
33
  }
34
+
35
+ /**
36
+ * Returns a Prvider, connected via a configured JSON URL or else
37
+ * the ethers.js default provider, using configured API keys.
38
+ * @returns <ethers.providers.Provider> An Eth node provider
39
+ */
40
+ export const setEthProvider = (): ethers.providers.Provider => {
41
+ if (provider) return provider
42
+ console.log(`setting new provider`)
43
+
44
+ // Use JSON URL if defined
45
+ // if ((hardhat as any).ethers) {
46
+ // console.log(`using hardhat.ethers provider`)
47
+ // provider = (hardhat as any).ethers.provider
48
+ // } else
49
+ if (process.env.ETH_PROVIDER_JSON_URL) {
50
+ console.log(`JSON URL provider at ${process.env.ETH_PROVIDER_JSON_URL}`)
51
+ provider = new ethers.providers.JsonRpcProvider({
52
+ url: process.env.ETH_PROVIDER_JSON_URL,
53
+ skipFetchSetup: true
54
+ })
55
+ } else {
56
+ // Otherwise, connect the default provider with ALchemy, Infura, or both
57
+ provider = ethers.providers.getDefaultProvider("homestead", {
58
+ alchemy: process.env.ETH_PROVIDER_ALCHEMY_API_KEY!,
59
+ infura: process.env.ETH_PROVIDER_INFURA_API_KEY!
60
+ })
61
+ }
62
+
63
+ return provider
64
+ }
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"
@@ -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
  }
@@ -0,0 +1 @@
1
+ declare module "@bandada/api-sdk"
@@ -1,4 +1,5 @@
1
1
  import { CeremonyInputData, CircuitDocument, ETagWithPartNumber } from "@devtion/actions"
2
+ import type { Groth16Proof, PublicSignals } from "snarkjs"
2
3
 
3
4
  /**
4
5
  * Group all the necessary data needed for running the `setupCeremony` cloud function.
@@ -138,3 +139,62 @@ export type FinalizeCircuitData = {
138
139
  bucketName: string
139
140
  beacon: string
140
141
  }
142
+
143
+ /**
144
+ * Group all the necessary data needed for running the `bandadaValidateProof` cloud function.
145
+ * @typedef {Object} BandadaValidateProof
146
+ * @property {string} merkleTreeRoot - the merkle tree root of the group.
147
+ * @property {string} nullifierHash - the nullifier hash of the member.
148
+ * @property {string} externalNullifier - the external nullifier of the member.
149
+ * @property {PackedProof} proof - the packed proof generated on the client.
150
+ */
151
+ export type BandadaValidateProof = {
152
+ proof: Groth16Proof
153
+ publicSignals: PublicSignals
154
+ }
155
+
156
+ /**
157
+ * Define the return object of the function that verifies the Bandada membership and proof.
158
+ * @typedef {Object} VerifiedBandadaResponse
159
+ * @property {boolean} valid - true if the proof is valid and the user is a member of the group; otherwise false.
160
+ * @property {string} message - a message describing the result of the verification.
161
+ * @property {string} token - the custom access token.
162
+ */
163
+ export type VerifiedBandadaResponse = {
164
+ valid: boolean
165
+ message: string
166
+ token: string
167
+ }
168
+
169
+ /**
170
+ * Define the check nonce object for the cloud function
171
+ * @typedef {Object} CheckNonceOfSIWEAddressRequest
172
+ * @property {string} auth0Token - token from the device flow authentication
173
+ */
174
+ export type CheckNonceOfSIWEAddressRequest = {
175
+ auth0Token: string
176
+ }
177
+
178
+ /**
179
+ * Define the check nonce response object of the cloud function
180
+ * @typedef {Object} CheckNonceOfSIWEAddressResponse
181
+ * @property {boolean} valid - if the checking result was valid or not
182
+ * @property {string} message - informative message
183
+ * @property {string} token - token to sign in
184
+ */
185
+ export type CheckNonceOfSIWEAddressResponse = {
186
+ valid: boolean
187
+ message?: string
188
+ token?: string
189
+ }
190
+ /**
191
+ * Define the response from auth0 /userinfo endpoint
192
+ *
193
+ */
194
+ export type Auth0UserInfo = {
195
+ sub: string
196
+ nickname: string
197
+ name: string
198
+ picture: string
199
+ updated_at: string
200
+ }