@devtion/backend 0.0.0-92056fa → 0.0.0-9843891
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 +7 -7
- package/dist/src/functions/index.js +413 -129
- package/dist/src/functions/index.mjs +416 -134
- package/dist/types/functions/bandada.d.ts +4 -0
- package/dist/types/functions/bandada.d.ts.map +1 -0
- package/dist/types/functions/ceremony.d.ts.map +1 -1
- package/dist/types/functions/circuit.d.ts.map +1 -1
- package/dist/types/functions/index.d.ts +2 -0
- package/dist/types/functions/index.d.ts.map +1 -1
- package/dist/types/functions/siwe.d.ts +4 -0
- package/dist/types/functions/siwe.d.ts.map +1 -0
- 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 +2 -1
- package/dist/types/lib/errors.d.ts.map +1 -1
- package/dist/types/lib/services.d.ts +7 -0
- package/dist/types/lib/services.d.ts.map +1 -1
- package/dist/types/lib/utils.d.ts.map +1 -1
- package/dist/types/types/index.d.ts +56 -0
- package/dist/types/types/index.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/functions/bandada.ts +155 -0
- package/src/functions/ceremony.ts +11 -6
- package/src/functions/circuit.ts +140 -118
- package/src/functions/index.ts +2 -0
- package/src/functions/participant.ts +15 -15
- package/src/functions/siwe.ts +77 -0
- package/src/functions/storage.ts +11 -8
- package/src/functions/timeout.ts +7 -5
- package/src/functions/user.ts +22 -12
- package/src/lib/errors.ts +6 -1
- package/src/lib/services.ts +36 -0
- package/src/lib/utils.ts +10 -8
- package/src/types/declarations.d.ts +1 -0
- package/src/types/index.ts +60 -0
package/src/functions/timeout.ts
CHANGED
|
@@ -42,7 +42,7 @@ dotenv.config()
|
|
|
42
42
|
export const checkAndRemoveBlockingContributor = functions
|
|
43
43
|
.region("europe-west1")
|
|
44
44
|
.runWith({
|
|
45
|
-
memory: "
|
|
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: "
|
|
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
|
|
package/src/functions/user.ts
CHANGED
|
@@ -18,7 +18,7 @@ dotenv.config()
|
|
|
18
18
|
export const registerAuthUser = functions
|
|
19
19
|
.region("europe-west1")
|
|
20
20
|
.runWith({
|
|
21
|
-
memory: "
|
|
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 =
|
|
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 ${
|
|
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(
|
|
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: "
|
|
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
|
|
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
|
|
package/src/lib/services.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
declare module "@bandada/api-sdk"
|
package/src/types/index.ts
CHANGED
|
@@ -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
|
+
}
|