@devtion/backend 0.0.0-57a8ab9 → 0.0.0-671e653

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.
@@ -27,6 +27,7 @@ var path = require('path');
27
27
  var os = require('os');
28
28
  var clientSsm = require('@aws-sdk/client-ssm');
29
29
  var clientEc2 = require('@aws-sdk/client-ec2');
30
+ var ethers = require('ethers');
30
31
  var functionsV1 = require('firebase-functions/v1');
31
32
  var functionsV2 = require('firebase-functions/v2');
32
33
  var timerNode = require('timer-node');
@@ -166,6 +167,8 @@ const COMMON_ERRORS = {
166
167
  CM_INVALID_COMMAND_EXECUTION: makeError("unknown", "There was an error while executing the command on the VM", "Please, contact the coordinator if the error persists.")
167
168
  };
168
169
 
170
+ dotenv.config();
171
+ let provider;
169
172
  /**
170
173
  * Return a configured and connected instance of the AWS S3 client.
171
174
  * @dev this method check and utilize the environment variables to configure the connection
@@ -188,6 +191,36 @@ const getS3Client = async () => {
188
191
  region: process.env.AWS_REGION
189
192
  });
190
193
  };
194
+ /**
195
+ * Returns a Prvider, connected via a configured JSON URL or else
196
+ * the ethers.js default provider, using configured API keys.
197
+ * @returns <ethers.providers.Provider> An Eth node provider
198
+ */
199
+ const setEthProvider = () => {
200
+ if (provider)
201
+ return provider;
202
+ console.log(`setting new provider`);
203
+ // Use JSON URL if defined
204
+ // if ((hardhat as any).ethers) {
205
+ // console.log(`using hardhat.ethers provider`)
206
+ // provider = (hardhat as any).ethers.provider
207
+ // } else
208
+ if (process.env.ETH_PROVIDER_JSON_URL) {
209
+ console.log(`JSON URL provider at ${process.env.ETH_PROVIDER_JSON_URL}`);
210
+ provider = new ethers.providers.JsonRpcProvider({
211
+ url: process.env.ETH_PROVIDER_JSON_URL,
212
+ skipFetchSetup: true
213
+ });
214
+ }
215
+ else {
216
+ // Otherwise, connect the default provider with ALchemy, Infura, or both
217
+ provider = ethers.providers.getDefaultProvider("homestead", {
218
+ alchemy: process.env.ETH_PROVIDER_ALCHEMY_API_KEY,
219
+ infura: process.env.ETH_PROVIDER_INFURA_API_KEY
220
+ });
221
+ }
222
+ return provider;
223
+ };
191
224
 
192
225
  dotenv.config();
193
226
  /**
@@ -2551,6 +2584,74 @@ const bandadaValidateProof = functions__namespace
2551
2584
  };
2552
2585
  });
2553
2586
 
2587
+ dotenv.config();
2588
+ const checkNonceOfSIWEAddress = functions__namespace
2589
+ .region("europe-west1")
2590
+ .runWith({ memory: "1GB" })
2591
+ .https.onCall(async (data) => {
2592
+ try {
2593
+ const { auth0Token } = data;
2594
+ const result = (await fetch(`${process.env.AUTH0_APPLICATION_URL}/userinfo`, {
2595
+ method: "GET",
2596
+ headers: {
2597
+ "content-type": "application/json",
2598
+ authorization: `Bearer ${auth0Token}`
2599
+ }
2600
+ }).then((_res) => _res.json()));
2601
+ if (!result.sub) {
2602
+ return {
2603
+ valid: false,
2604
+ message: "No user detected. Please check device flow token"
2605
+ };
2606
+ }
2607
+ const auth$1 = auth.getAuth();
2608
+ // check nonce
2609
+ const parts = result.sub.split("|");
2610
+ const address = decodeURIComponent(parts[2]).split("eip155:534352:")[1];
2611
+ const minimumNonce = Number(process.env.ETH_MINIMUM_NONCE);
2612
+ const nonceBlockHeight = "latest"; // process.env.ETH_NONCE_BLOCK_HEIGHT
2613
+ // look up nonce for address @block
2614
+ let nonceOk = true;
2615
+ if (minimumNonce > 0) {
2616
+ const provider = setEthProvider();
2617
+ console.log(`got provider - block # ${await provider.getBlockNumber()}`);
2618
+ const nonce = await provider.getTransactionCount(address, nonceBlockHeight);
2619
+ console.log(`nonce ${nonce}`);
2620
+ nonceOk = nonce >= minimumNonce;
2621
+ }
2622
+ console.log(`checking nonce ${nonceOk}`);
2623
+ if (!nonceOk) {
2624
+ return {
2625
+ valid: false,
2626
+ message: "Eth address does not meet the nonce requirements"
2627
+ };
2628
+ }
2629
+ try {
2630
+ await admin.auth().createUser({
2631
+ displayName: address,
2632
+ uid: address
2633
+ });
2634
+ }
2635
+ catch (error) {
2636
+ // if user already exist then just pass
2637
+ if (error.code !== "auth/uid-already-exists") {
2638
+ throw new Error(error);
2639
+ }
2640
+ }
2641
+ const token = await auth$1.createCustomToken(address);
2642
+ return {
2643
+ valid: true,
2644
+ token
2645
+ };
2646
+ }
2647
+ catch (error) {
2648
+ return {
2649
+ valid: false,
2650
+ message: `Something went wrong ${error}`
2651
+ };
2652
+ }
2653
+ });
2654
+
2554
2655
  dotenv.config();
2555
2656
  /**
2556
2657
  * Check and remove the current contributor if it doesn't complete the contribution on the specified amount of time.
@@ -2756,6 +2857,7 @@ exports.bandadaValidateProof = bandadaValidateProof;
2756
2857
  exports.checkAndPrepareCoordinatorForFinalization = checkAndPrepareCoordinatorForFinalization;
2757
2858
  exports.checkAndRemoveBlockingContributor = checkAndRemoveBlockingContributor;
2758
2859
  exports.checkIfObjectExist = checkIfObjectExist;
2860
+ exports.checkNonceOfSIWEAddress = checkNonceOfSIWEAddress;
2759
2861
  exports.checkParticipantForCeremony = checkParticipantForCeremony;
2760
2862
  exports.completeMultiPartUpload = completeMultiPartUpload;
2761
2863
  exports.coordinateCeremonyParticipant = coordinateCeremonyParticipant;
@@ -25,6 +25,7 @@ import path from 'path';
25
25
  import os from 'os';
26
26
  import { SSMClient, CommandInvocationStatus } from '@aws-sdk/client-ssm';
27
27
  import { EC2Client } from '@aws-sdk/client-ec2';
28
+ import ethers from 'ethers';
28
29
  import * as functionsV1 from 'firebase-functions/v1';
29
30
  import * as functionsV2 from 'firebase-functions/v2';
30
31
  import { Timer } from 'timer-node';
@@ -143,6 +144,8 @@ const COMMON_ERRORS = {
143
144
  CM_INVALID_COMMAND_EXECUTION: makeError("unknown", "There was an error while executing the command on the VM", "Please, contact the coordinator if the error persists.")
144
145
  };
145
146
 
147
+ dotenv.config();
148
+ let provider;
146
149
  /**
147
150
  * Return a configured and connected instance of the AWS S3 client.
148
151
  * @dev this method check and utilize the environment variables to configure the connection
@@ -165,6 +168,36 @@ const getS3Client = async () => {
165
168
  region: process.env.AWS_REGION
166
169
  });
167
170
  };
171
+ /**
172
+ * Returns a Prvider, connected via a configured JSON URL or else
173
+ * the ethers.js default provider, using configured API keys.
174
+ * @returns <ethers.providers.Provider> An Eth node provider
175
+ */
176
+ const setEthProvider = () => {
177
+ if (provider)
178
+ return provider;
179
+ console.log(`setting new provider`);
180
+ // Use JSON URL if defined
181
+ // if ((hardhat as any).ethers) {
182
+ // console.log(`using hardhat.ethers provider`)
183
+ // provider = (hardhat as any).ethers.provider
184
+ // } else
185
+ if (process.env.ETH_PROVIDER_JSON_URL) {
186
+ console.log(`JSON URL provider at ${process.env.ETH_PROVIDER_JSON_URL}`);
187
+ provider = new ethers.providers.JsonRpcProvider({
188
+ url: process.env.ETH_PROVIDER_JSON_URL,
189
+ skipFetchSetup: true
190
+ });
191
+ }
192
+ else {
193
+ // Otherwise, connect the default provider with ALchemy, Infura, or both
194
+ provider = ethers.providers.getDefaultProvider("homestead", {
195
+ alchemy: process.env.ETH_PROVIDER_ALCHEMY_API_KEY,
196
+ infura: process.env.ETH_PROVIDER_INFURA_API_KEY
197
+ });
198
+ }
199
+ return provider;
200
+ };
168
201
 
169
202
  dotenv.config();
170
203
  /**
@@ -2528,6 +2561,74 @@ const bandadaValidateProof = functions
2528
2561
  };
2529
2562
  });
2530
2563
 
2564
+ dotenv.config();
2565
+ const checkNonceOfSIWEAddress = functions
2566
+ .region("europe-west1")
2567
+ .runWith({ memory: "1GB" })
2568
+ .https.onCall(async (data) => {
2569
+ try {
2570
+ const { auth0Token } = data;
2571
+ const result = (await fetch(`${process.env.AUTH0_APPLICATION_URL}/userinfo`, {
2572
+ method: "GET",
2573
+ headers: {
2574
+ "content-type": "application/json",
2575
+ authorization: `Bearer ${auth0Token}`
2576
+ }
2577
+ }).then((_res) => _res.json()));
2578
+ if (!result.sub) {
2579
+ return {
2580
+ valid: false,
2581
+ message: "No user detected. Please check device flow token"
2582
+ };
2583
+ }
2584
+ const auth = getAuth();
2585
+ // check nonce
2586
+ const parts = result.sub.split("|");
2587
+ const address = decodeURIComponent(parts[2]).split("eip155:534352:")[1];
2588
+ const minimumNonce = Number(process.env.ETH_MINIMUM_NONCE);
2589
+ const nonceBlockHeight = "latest"; // process.env.ETH_NONCE_BLOCK_HEIGHT
2590
+ // look up nonce for address @block
2591
+ let nonceOk = true;
2592
+ if (minimumNonce > 0) {
2593
+ const provider = setEthProvider();
2594
+ console.log(`got provider - block # ${await provider.getBlockNumber()}`);
2595
+ const nonce = await provider.getTransactionCount(address, nonceBlockHeight);
2596
+ console.log(`nonce ${nonce}`);
2597
+ nonceOk = nonce >= minimumNonce;
2598
+ }
2599
+ console.log(`checking nonce ${nonceOk}`);
2600
+ if (!nonceOk) {
2601
+ return {
2602
+ valid: false,
2603
+ message: "Eth address does not meet the nonce requirements"
2604
+ };
2605
+ }
2606
+ try {
2607
+ await admin.auth().createUser({
2608
+ displayName: address,
2609
+ uid: address
2610
+ });
2611
+ }
2612
+ catch (error) {
2613
+ // if user already exist then just pass
2614
+ if (error.code !== "auth/uid-already-exists") {
2615
+ throw new Error(error);
2616
+ }
2617
+ }
2618
+ const token = await auth.createCustomToken(address);
2619
+ return {
2620
+ valid: true,
2621
+ token
2622
+ };
2623
+ }
2624
+ catch (error) {
2625
+ return {
2626
+ valid: false,
2627
+ message: `Something went wrong ${error}`
2628
+ };
2629
+ }
2630
+ });
2631
+
2531
2632
  dotenv.config();
2532
2633
  /**
2533
2634
  * Check and remove the current contributor if it doesn't complete the contribution on the specified amount of time.
@@ -2729,4 +2830,4 @@ const resumeContributionAfterTimeoutExpiration = functions
2729
2830
 
2730
2831
  admin.initializeApp();
2731
2832
 
2732
- export { bandadaValidateProof, checkAndPrepareCoordinatorForFinalization, checkAndRemoveBlockingContributor, checkIfObjectExist, checkParticipantForCeremony, completeMultiPartUpload, coordinateCeremonyParticipant, createBucket, finalizeCeremony, finalizeCircuit, generateGetObjectPreSignedUrl, generatePreSignedUrlsParts, initEmptyWaitingQueueForCircuit, permanentlyStoreCurrentContributionTimeAndHash, processSignUpWithCustomClaims, progressToNextCircuitForContribution, progressToNextContributionStep, refreshParticipantAfterContributionVerification, registerAuthUser, resumeContributionAfterTimeoutExpiration, setupCeremony, startCeremony, startMultiPartUpload, stopCeremony, temporaryStoreCurrentContributionMultiPartUploadId, temporaryStoreCurrentContributionUploadedChunkData, verifycontribution };
2833
+ export { bandadaValidateProof, checkAndPrepareCoordinatorForFinalization, checkAndRemoveBlockingContributor, checkIfObjectExist, checkNonceOfSIWEAddress, checkParticipantForCeremony, completeMultiPartUpload, coordinateCeremonyParticipant, createBucket, finalizeCeremony, finalizeCircuit, generateGetObjectPreSignedUrl, generatePreSignedUrlsParts, initEmptyWaitingQueueForCircuit, permanentlyStoreCurrentContributionTimeAndHash, processSignUpWithCustomClaims, progressToNextCircuitForContribution, progressToNextContributionStep, refreshParticipantAfterContributionVerification, registerAuthUser, resumeContributionAfterTimeoutExpiration, setupCeremony, startCeremony, startMultiPartUpload, stopCeremony, temporaryStoreCurrentContributionMultiPartUploadId, temporaryStoreCurrentContributionUploadedChunkData, verifycontribution };
@@ -1 +1 @@
1
- {"version":3,"file":"bandada.d.ts","sourceRoot":"","sources":["../../../src/functions/bandada.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,SAAS,MAAM,oBAAoB,CAAA;AA8G/C,eAAO,MAAM,oBAAoB,mDA0C3B,CAAA;AAEN,eAAe,oBAAoB,CAAA"}
1
+ {"version":3,"file":"bandada.d.ts","sourceRoot":"","sources":["../../../src/functions/bandada.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,SAAS,MAAM,oBAAoB,CAAA;AA6G/C,eAAO,MAAM,oBAAoB,mDA0C3B,CAAA;AAEN,eAAe,oBAAoB,CAAA"}
@@ -4,5 +4,6 @@ export { checkParticipantForCeremony, progressToNextContributionStep, permanentl
4
4
  export { coordinateCeremonyParticipant, verifycontribution, refreshParticipantAfterContributionVerification, finalizeCircuit } from "./circuit";
5
5
  export { createBucket, checkIfObjectExist, generateGetObjectPreSignedUrl, startMultiPartUpload, generatePreSignedUrlsParts, completeMultiPartUpload } from "./storage";
6
6
  export { bandadaValidateProof } from "./bandada";
7
+ export { checkNonceOfSIWEAddress } from "./siwe";
7
8
  export { checkAndRemoveBlockingContributor, resumeContributionAfterTimeoutExpiration } from "./timeout";
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/functions/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,6BAA6B,EAAE,MAAM,QAAQ,CAAA;AACxE,OAAO,EACH,aAAa,EACb,YAAY,EACZ,aAAa,EACb,+BAA+B,EAC/B,gBAAgB,EACnB,MAAM,YAAY,CAAA;AACnB,OAAO,EACH,2BAA2B,EAC3B,8BAA8B,EAC9B,8CAA8C,EAC9C,kDAAkD,EAClD,kDAAkD,EAClD,oCAAoC,EACpC,yCAAyC,EAC5C,MAAM,eAAe,CAAA;AACtB,OAAO,EACH,6BAA6B,EAC7B,kBAAkB,EAClB,+CAA+C,EAC/C,eAAe,EAClB,MAAM,WAAW,CAAA;AAClB,OAAO,EACH,YAAY,EACZ,kBAAkB,EAClB,6BAA6B,EAC7B,oBAAoB,EACpB,0BAA0B,EAC1B,uBAAuB,EAC1B,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAChD,OAAO,EAAE,iCAAiC,EAAE,wCAAwC,EAAE,MAAM,WAAW,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/functions/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,6BAA6B,EAAE,MAAM,QAAQ,CAAA;AACxE,OAAO,EACH,aAAa,EACb,YAAY,EACZ,aAAa,EACb,+BAA+B,EAC/B,gBAAgB,EACnB,MAAM,YAAY,CAAA;AACnB,OAAO,EACH,2BAA2B,EAC3B,8BAA8B,EAC9B,8CAA8C,EAC9C,kDAAkD,EAClD,kDAAkD,EAClD,oCAAoC,EACpC,yCAAyC,EAC5C,MAAM,eAAe,CAAA;AACtB,OAAO,EACH,6BAA6B,EAC7B,kBAAkB,EAClB,+CAA+C,EAC/C,eAAe,EAClB,MAAM,WAAW,CAAA;AAClB,OAAO,EACH,YAAY,EACZ,kBAAkB,EAClB,6BAA6B,EAC7B,oBAAoB,EACpB,0BAA0B,EAC1B,uBAAuB,EAC1B,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAA;AAChD,OAAO,EAAE,uBAAuB,EAAE,MAAM,QAAQ,CAAA;AAChD,OAAO,EAAE,iCAAiC,EAAE,wCAAwC,EAAE,MAAM,WAAW,CAAA"}
@@ -0,0 +1,4 @@
1
+ import * as functions from "firebase-functions";
2
+ export declare const checkNonceOfSIWEAddress: functions.HttpsFunction & functions.Runnable<any>;
3
+ export default checkNonceOfSIWEAddress;
4
+ //# sourceMappingURL=siwe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"siwe.d.ts","sourceRoot":"","sources":["../../../src/functions/siwe.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,SAAS,MAAM,oBAAoB,CAAA;AAQ/C,eAAO,MAAM,uBAAuB,mDAgE9B,CAAA;AAEN,eAAe,uBAAuB,CAAA"}
@@ -1,3 +1,4 @@
1
+ import ethers from "ethers";
1
2
  import { S3Client } from "@aws-sdk/client-s3";
2
3
  /**
3
4
  * Return a configured and connected instance of the AWS S3 client.
@@ -6,4 +7,10 @@ import { S3Client } from "@aws-sdk/client-s3";
6
7
  * @returns <Promise<S3Client>> - the instance of the connected S3 Client instance.
7
8
  */
8
9
  export declare const getS3Client: () => Promise<S3Client>;
10
+ /**
11
+ * Returns a Prvider, connected via a configured JSON URL or else
12
+ * the ethers.js default provider, using configured API keys.
13
+ * @returns <ethers.providers.Provider> An Eth node provider
14
+ */
15
+ export declare const setEthProvider: () => ethers.providers.Provider;
9
16
  //# sourceMappingURL=services.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../../src/lib/services.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAG7C;;;;;GAKG;AACH,eAAO,MAAM,WAAW,QAAa,QAAQ,QAAQ,CAkBpD,CAAA"}
1
+ {"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../../src/lib/services.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,QAAQ,CAAA;AAC3B,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAM7C;;;;;GAKG;AACH,eAAO,MAAM,WAAW,QAAa,QAAQ,QAAQ,CAkBpD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,QAAO,OAAO,SAAS,CAAC,QAwBlD,CAAA"}
@@ -152,4 +152,35 @@ export type VerifiedBandadaResponse = {
152
152
  message: string;
153
153
  token: string;
154
154
  };
155
+ /**
156
+ * Define the check nonce object for the cloud function
157
+ * @typedef {Object} CheckNonceOfSIWEAddressRequest
158
+ * @property {string} auth0Token - token from the device flow authentication
159
+ */
160
+ export type CheckNonceOfSIWEAddressRequest = {
161
+ auth0Token: string;
162
+ };
163
+ /**
164
+ * Define the check nonce response object of the cloud function
165
+ * @typedef {Object} CheckNonceOfSIWEAddressResponse
166
+ * @property {boolean} valid - if the checking result was valid or not
167
+ * @property {string} message - informative message
168
+ * @property {string} token - token to sign in
169
+ */
170
+ export type CheckNonceOfSIWEAddressResponse = {
171
+ valid: boolean;
172
+ message?: string;
173
+ token?: string;
174
+ };
175
+ /**
176
+ * Define the response from auth0 /userinfo endpoint
177
+ *
178
+ */
179
+ export type Auth0UserInfo = {
180
+ sub: string;
181
+ nickname: string;
182
+ name: string;
183
+ picture: string;
184
+ updated_at: string;
185
+ };
155
186
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACxF,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE1D;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC5B,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,cAAc,EAAE,MAAM,CAAA;IACtB,QAAQ,EAAE,KAAK,CAAC,eAAe,CAAC,CAAA;CACnC,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC3B,UAAU,EAAE,MAAM,CAAA;CACrB,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CACpB,CAAA;AAED;;;;;;GAMG;AACH,MAAM,MAAM,wBAAwB,GAAG,sBAAsB,GAAG;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,8BAA8B,GAAG,sBAAsB,GAAG;IAClE,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,2BAA2B,GAAG,sBAAsB,GAAG;IAC/D,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,KAAK,CAAC,kBAAkB,CAAC,CAAA;IAChC,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED;;;;;;GAMG;AACH,MAAM,MAAM,8CAA8C,GAAG;IACzD,UAAU,EAAE,MAAM,CAAA;IAClB,2BAA2B,EAAE,MAAM,CAAA;IACnC,gBAAgB,EAAE,MAAM,CAAA;CAC3B,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,kDAAkD,GAAG;IAC7D,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,kDAAkD,GAAG;IAC7D,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,kBAAkB,CAAA;CAC5B,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,kCAAkC,EAAE,MAAM,CAAA;CAC7C,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;CACjB,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG;IAC/B,KAAK,EAAE,YAAY,CAAA;IACnB,aAAa,EAAE,aAAa,CAAA;CAC/B,CAAA;AAED;;;;;;GAMG;AACH,MAAM,MAAM,uBAAuB,GAAG;IAClC,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;CAChB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACxF,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE1D;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC5B,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,cAAc,EAAE,MAAM,CAAA;IACtB,QAAQ,EAAE,KAAK,CAAC,eAAe,CAAC,CAAA;CACnC,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC3B,UAAU,EAAE,MAAM,CAAA;CACrB,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CACpB,CAAA;AAED;;;;;;GAMG;AACH,MAAM,MAAM,wBAAwB,GAAG,sBAAsB,GAAG;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,8BAA8B,GAAG,sBAAsB,GAAG;IAClE,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,2BAA2B,GAAG,sBAAsB,GAAG;IAC/D,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,KAAK,CAAC,kBAAkB,CAAC,CAAA;IAChC,UAAU,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAED;;;;;;GAMG;AACH,MAAM,MAAM,8CAA8C,GAAG;IACzD,UAAU,EAAE,MAAM,CAAA;IAClB,2BAA2B,EAAE,MAAM,CAAA;IACnC,gBAAgB,EAAE,MAAM,CAAA;CAC3B,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,kDAAkD,GAAG;IAC7D,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,kDAAkD,GAAG;IAC7D,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,EAAE,kBAAkB,CAAA;CAC5B,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,sBAAsB,GAAG;IACjC,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,kCAAkC,EAAE,MAAM,CAAA;CAC7C,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,MAAM,CAAA;CACjB,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG;IAC/B,KAAK,EAAE,YAAY,CAAA;IACnB,aAAa,EAAE,aAAa,CAAA;CAC/B,CAAA;AAED;;;;;;GAMG;AACH,MAAM,MAAM,uBAAuB,GAAG;IAClC,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;CAChB,CAAA;AAED;;;;GAIG;AACH,MAAM,MAAM,8BAA8B,GAAG;IACzC,UAAU,EAAE,MAAM,CAAA;CACrB,CAAA;AAED;;;;;;GAMG;AACH,MAAM,MAAM,+BAA+B,GAAG;IAC1C,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AACD;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG;IACxB,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;CACrB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devtion/backend",
3
- "version": "0.0.0-57a8ab9",
3
+ "version": "0.0.0-671e653",
4
4
  "description": "MPC Phase 2 backend for Firebase services management",
5
5
  "repository": "git@github.com:privacy-scaling-explorations/p0tion.git",
6
6
  "homepage": "https://github.com/privacy-scaling-explorations/p0tion",
@@ -86,5 +86,5 @@
86
86
  "publishConfig": {
87
87
  "access": "public"
88
88
  },
89
- "gitHead": "6bddf60f1121786c19ad4437e0448de4c859b829"
89
+ "gitHead": "c9c799447bc2e3abd6b665fe09622ac724ea9b79"
90
90
  }
@@ -3,9 +3,8 @@ import * as functions from "firebase-functions"
3
3
  import { ApiSdk } from "@bandada/api-sdk"
4
4
  import { groth16 } from "snarkjs"
5
5
  import { getAuth } from "firebase-admin/auth"
6
- import { BandadaValidateProof, VerifiedBandadaResponse } from "../types/index"
7
-
8
6
  import admin from "firebase-admin"
7
+ import { BandadaValidateProof, VerifiedBandadaResponse } from "../types/index"
9
8
 
10
9
  const VKEY_DATA = {
11
10
  protocol: "groth16",
@@ -32,6 +32,7 @@ export {
32
32
  completeMultiPartUpload
33
33
  } from "./storage"
34
34
  export { bandadaValidateProof } from "./bandada"
35
+ export { checkNonceOfSIWEAddress } from "./siwe"
35
36
  export { checkAndRemoveBlockingContributor, resumeContributionAfterTimeoutExpiration } from "./timeout"
36
37
 
37
38
  admin.initializeApp()
@@ -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("eip155:534352:")[1]
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
@@ -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
+ }
@@ -165,3 +165,36 @@ export type VerifiedBandadaResponse = {
165
165
  message: string
166
166
  token: string
167
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
+ }