@devtion/backend 0.0.0-c749be4 → 0.0.0-e312890
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/dist/src/functions/index.js +561 -309
- package/dist/src/functions/index.mjs +562 -312
- package/dist/types/functions/bandada.d.ts +4 -0
- package/dist/types/functions/bandada.d.ts.map +1 -0
- 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/lib/errors.d.ts +1 -1
- package/dist/types/lib/services.d.ts +7 -0
- package/dist/types/lib/services.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 +5 -5
- package/src/functions/circuit.ts +373 -369
- package/src/functions/index.ts +2 -0
- package/src/functions/participant.ts +7 -7
- package/src/functions/siwe.ts +77 -0
- package/src/functions/storage.ts +6 -6
- package/src/functions/timeout.ts +2 -2
- package/src/functions/user.ts +4 -4
- package/src/lib/errors.ts +1 -1
- package/src/lib/services.ts +36 -0
- package/src/types/declarations.d.ts +1 -0
- package/src/types/index.ts +60 -0
package/src/functions/index.ts
CHANGED
|
@@ -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()
|
|
@@ -46,7 +46,7 @@ dotenv.config()
|
|
|
46
46
|
export const checkParticipantForCeremony = functions
|
|
47
47
|
.region("europe-west1")
|
|
48
48
|
.runWith({
|
|
49
|
-
memory: "
|
|
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))
|
|
@@ -177,7 +177,7 @@ export const checkParticipantForCeremony = functions
|
|
|
177
177
|
export const progressToNextCircuitForContribution = functions
|
|
178
178
|
.region("europe-west1")
|
|
179
179
|
.runWith({
|
|
180
|
-
memory: "
|
|
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))
|
|
@@ -235,7 +235,7 @@ export const progressToNextCircuitForContribution = functions
|
|
|
235
235
|
export const progressToNextContributionStep = functions
|
|
236
236
|
.region("europe-west1")
|
|
237
237
|
.runWith({
|
|
238
|
-
memory: "
|
|
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))
|
|
@@ -298,7 +298,7 @@ export const progressToNextContributionStep = functions
|
|
|
298
298
|
export const permanentlyStoreCurrentContributionTimeAndHash = functions
|
|
299
299
|
.region("europe-west1")
|
|
300
300
|
.runWith({
|
|
301
|
-
memory: "
|
|
301
|
+
memory: "1GB"
|
|
302
302
|
})
|
|
303
303
|
.https.onCall(
|
|
304
304
|
async (data: PermanentlyStoreCurrentContributionTimeAndHash, context: functions.https.CallableContext) => {
|
|
@@ -357,7 +357,7 @@ export const permanentlyStoreCurrentContributionTimeAndHash = functions
|
|
|
357
357
|
export const temporaryStoreCurrentContributionMultiPartUploadId = functions
|
|
358
358
|
.region("europe-west1")
|
|
359
359
|
.runWith({
|
|
360
|
-
memory: "
|
|
360
|
+
memory: "1GB"
|
|
361
361
|
})
|
|
362
362
|
.https.onCall(
|
|
363
363
|
async (data: TemporaryStoreCurrentContributionMultiPartUploadId, context: functions.https.CallableContext) => {
|
|
@@ -411,7 +411,7 @@ export const temporaryStoreCurrentContributionMultiPartUploadId = functions
|
|
|
411
411
|
export const temporaryStoreCurrentContributionUploadedChunkData = functions
|
|
412
412
|
.region("europe-west1")
|
|
413
413
|
.runWith({
|
|
414
|
-
memory: "
|
|
414
|
+
memory: "1GB"
|
|
415
415
|
})
|
|
416
416
|
.https.onCall(
|
|
417
417
|
async (data: TemporaryStoreCurrentContributionUploadedChunkData, context: functions.https.CallableContext) => {
|
|
@@ -471,7 +471,7 @@ export const temporaryStoreCurrentContributionUploadedChunkData = functions
|
|
|
471
471
|
export const checkAndPrepareCoordinatorForFinalization = functions
|
|
472
472
|
.region("europe-west1")
|
|
473
473
|
.runWith({
|
|
474
|
-
memory: "
|
|
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
|
package/src/functions/storage.ts
CHANGED
|
@@ -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: "
|
|
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.
|
|
@@ -238,7 +238,7 @@ export const createBucket = functions
|
|
|
238
238
|
export const checkIfObjectExist = functions
|
|
239
239
|
.region("europe-west1")
|
|
240
240
|
.runWith({
|
|
241
|
-
memory: "
|
|
241
|
+
memory: "1GB"
|
|
242
242
|
})
|
|
243
243
|
.https.onCall(async (data: BucketAndObjectKeyData, context: functions.https.CallableContext): Promise<boolean> => {
|
|
244
244
|
// Check if the user has the coordinator claim.
|
|
@@ -294,7 +294,7 @@ export const checkIfObjectExist = functions
|
|
|
294
294
|
export const generateGetObjectPreSignedUrl = functions
|
|
295
295
|
.region("europe-west1")
|
|
296
296
|
.runWith({
|
|
297
|
-
memory: "
|
|
297
|
+
memory: "1GB"
|
|
298
298
|
})
|
|
299
299
|
.https.onCall(async (data: BucketAndObjectKeyData, context: functions.https.CallableContext): Promise<any> => {
|
|
300
300
|
if (!context.auth) logAndThrowError(COMMON_ERRORS.CM_NOT_AUTHENTICATED)
|
|
@@ -341,7 +341,7 @@ export const generateGetObjectPreSignedUrl = functions
|
|
|
341
341
|
export const startMultiPartUpload = functions
|
|
342
342
|
.region("europe-west1")
|
|
343
343
|
.runWith({
|
|
344
|
-
memory: "
|
|
344
|
+
memory: "2GB"
|
|
345
345
|
})
|
|
346
346
|
.https.onCall(async (data: StartMultiPartUploadData, context: functions.https.CallableContext): Promise<any> => {
|
|
347
347
|
if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
|
|
@@ -409,7 +409,7 @@ export const startMultiPartUpload = functions
|
|
|
409
409
|
export const generatePreSignedUrlsParts = functions
|
|
410
410
|
.region("europe-west1")
|
|
411
411
|
.runWith({
|
|
412
|
-
memory: "
|
|
412
|
+
memory: "1GB",
|
|
413
413
|
timeoutSeconds: 300
|
|
414
414
|
})
|
|
415
415
|
.https.onCall(
|
|
@@ -487,7 +487,7 @@ export const generatePreSignedUrlsParts = functions
|
|
|
487
487
|
export const completeMultiPartUpload = functions
|
|
488
488
|
.region("europe-west1")
|
|
489
489
|
.runWith({
|
|
490
|
-
memory: "
|
|
490
|
+
memory: "2GB"
|
|
491
491
|
})
|
|
492
492
|
.https.onCall(async (data: CompleteMultiPartUploadData, context: functions.https.CallableContext): Promise<any> => {
|
|
493
493
|
if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
|
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 () => {
|
|
@@ -253,7 +253,7 @@ export const checkAndRemoveBlockingContributor = functions
|
|
|
253
253
|
export const resumeContributionAfterTimeoutExpiration = functions
|
|
254
254
|
.region("europe-west1")
|
|
255
255
|
.runWith({
|
|
256
|
-
memory: "
|
|
256
|
+
memory: "1GB"
|
|
257
257
|
})
|
|
258
258
|
.https.onCall(async (data: { ceremonyId: string }, context: functions.https.CallableContext): Promise<void> => {
|
|
259
259
|
if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
|
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) => {
|
|
@@ -55,7 +55,7 @@ export const registerAuthUser = functions
|
|
|
55
55
|
) {
|
|
56
56
|
const auth = admin.auth()
|
|
57
57
|
// if provider == github.com let's use our functions to check the user's reputation
|
|
58
|
-
if (user.providerData[0].providerId === "github.com") {
|
|
58
|
+
if (user.providerData.length > 0 && user.providerData[0].providerId === "github.com") {
|
|
59
59
|
const vars = getGitHubVariables()
|
|
60
60
|
|
|
61
61
|
// this return true or false
|
|
@@ -112,7 +112,7 @@ export const registerAuthUser = functions
|
|
|
112
112
|
encodedDisplayName,
|
|
113
113
|
// Metadata.
|
|
114
114
|
creationTime,
|
|
115
|
-
lastSignInTime,
|
|
115
|
+
lastSignInTime: lastSignInTime || creationTime,
|
|
116
116
|
// Optional.
|
|
117
117
|
email: email || "",
|
|
118
118
|
emailVerified: emailVerified || false,
|
|
@@ -136,7 +136,7 @@ export const registerAuthUser = functions
|
|
|
136
136
|
export const processSignUpWithCustomClaims = functions
|
|
137
137
|
.region("europe-west1")
|
|
138
138
|
.runWith({
|
|
139
|
-
memory: "
|
|
139
|
+
memory: "1GB"
|
|
140
140
|
})
|
|
141
141
|
.auth.user()
|
|
142
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
|
*/
|
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
|
+
}
|
|
@@ -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
|
+
}
|