@devtion/devcli 0.0.0-b499eaf → 0.0.0-c1f4cbe

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.
@@ -1,4 +1,5 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import { Dirent, Stats } from "fs";
3
4
  /**
4
5
  * Check a directory path.
@@ -35,6 +35,44 @@ export declare const setLocalAccessToken: (token: string) => void;
35
35
  * Delete the stored access token.
36
36
  */
37
37
  export declare const deleteLocalAccessToken: () => void;
38
+ /**
39
+ * Return the Bandada identity, if present.
40
+ * @returns <string | undefined> - the Bandada identity if present, otherwise undefined.
41
+ */
42
+ export declare const getLocalBandadaIdentity: () => string | unknown;
43
+ /**
44
+ * Check if the Bandada identity exists in the local storage.
45
+ * @returns <boolean>
46
+ */
47
+ export declare const checkLocalBandadaIdentity: () => boolean;
48
+ /**
49
+ * Set the Bandada identity.
50
+ * @param identity <string> - the Bandada identity to be stored.
51
+ */
52
+ export declare const setLocalBandadaIdentity: (identity: string) => void;
53
+ /**
54
+ * Delete the stored Bandada identity.
55
+ */
56
+ export declare const deleteLocalBandadaIdentity: () => void;
57
+ /**
58
+ * Return the authentication method, if present.
59
+ * @returns <string | undefined> - the authentication method if present, otherwise undefined.
60
+ */
61
+ export declare const getLocalAuthMethod: () => string | unknown;
62
+ /**
63
+ * Check if the authentication method exists in the local storage.
64
+ * @returns <boolean>
65
+ */
66
+ export declare const checkLocalAuthMethod: () => boolean;
67
+ /**
68
+ * Set the authentication method.
69
+ * @param method <string> - the authentication method to be stored.
70
+ */
71
+ export declare const setLocalAuthMethod: (method: string) => void;
72
+ /**
73
+ * Delete the stored authentication method.
74
+ */
75
+ export declare const deleteLocalAuthMethod: () => void;
38
76
  /**
39
77
  * Get the complete local file path.
40
78
  * @param cwd <string> - the current working directory path.
@@ -63,3 +63,66 @@ export type GithubGistFile = {
63
63
  raw_url: string;
64
64
  size: number;
65
65
  };
66
+ /**
67
+ * Define the return object of the function that verifies the Bandada membership and proof.
68
+ * @typedef {Object} VerifiedBandadaResponse
69
+ * @property {boolean} valid - true if the proof is valid and the user is a member of the group; otherwise false.
70
+ * @property {string} message - a message describing the result of the verification.
71
+ * @property {string} token - the custom access token.
72
+ */
73
+ export type VerifiedBandadaResponse = {
74
+ valid: boolean;
75
+ message: string;
76
+ token: string;
77
+ };
78
+ /**
79
+ * Define the return object of the device code uri request.
80
+ * @typedef {Object} OAuthDeviceCodeResponse
81
+ * @property {string} device_code - the device code.
82
+ * @property {string} user_code - the user code.
83
+ * @property {string} verification_uri - the verification uri.
84
+ * @property {number} expires_in - the expiration time in seconds.
85
+ * @property {number} interval - the interval time in seconds.
86
+ * @property {string} verification_uri_complete - the complete verification uri.
87
+ */
88
+ export type OAuthDeviceCodeResponse = {
89
+ device_code: string;
90
+ user_code: string;
91
+ verification_uri: string;
92
+ expires_in: number;
93
+ interval: number;
94
+ verification_uri_complete: string;
95
+ };
96
+ /**
97
+ * Define the return object of the polling endpoint
98
+ * @typedef {Object} OAuthTokenResponse
99
+ * @property {string} access_token - the resulting device flow token
100
+ * @property {string} token_type - token type
101
+ * @property {number} expires_in - when does the token expires
102
+ * @property {string} scope - the scope requested by the initial device flow endpoint
103
+ * @property {string} refresh_token - refresh token
104
+ * @property {string} id_token - id token
105
+ * @property {string} error - in case there was an error
106
+ * @property {string} error_description - error details
107
+ */
108
+ export type OAuthTokenResponse = {
109
+ access_token: string;
110
+ token_type: string;
111
+ expires_in: number;
112
+ scope: string;
113
+ refresh_token: string;
114
+ id_token: string;
115
+ error?: string;
116
+ error_description?: string;
117
+ };
118
+ /**
119
+ * @typedef {Object} CheckNonceOfSIWEAddressResponse
120
+ * @property {boolean} valid - if the checking was valid or not
121
+ * @property {string} message - more information about the validity
122
+ * @property {string} token - token to sign into Firebase
123
+ */
124
+ export type CheckNonceOfSIWEAddressResponse = {
125
+ valid: boolean;
126
+ message: string;
127
+ token: string;
128
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@devtion/devcli",
3
3
  "type": "module",
4
- "version": "0.0.0-b499eaf",
4
+ "version": "0.0.0-c1f4cbe",
5
5
  "description": "All-in-one interactive command-line for interfacing with zkSNARK Phase 2 Trusted Setup ceremonies",
6
6
  "repository": "git@github.com:privacy-scaling-explorations/p0tion.git",
7
7
  "homepage": "https://github.com/privacy-scaling-explorations/p0tion",
@@ -34,11 +34,14 @@
34
34
  "build:watch": "rollup -c rollup.config.ts -w --configPlugin typescript",
35
35
  "start": "ts-node --esm ./src/index.ts",
36
36
  "auth": "yarn start auth",
37
+ "auth:siwe": "yarn start auth-siwe",
38
+ "auth:bandada": "yarn start auth-bandada",
37
39
  "contribute": "yarn start contribute",
38
40
  "clean": "yarn start clean",
39
41
  "list": "yarn start list",
40
42
  "logout": "yarn start logout",
41
43
  "validate": "yarn start validate",
44
+ "ceremony:participants": "yarn start ceremony participants",
42
45
  "coordinate:setup": "yarn start coordinate setup",
43
46
  "coordinate:observe": "yarn start coordinate observe",
44
47
  "coordinate:finalize": "yarn start coordinate finalize",
@@ -57,6 +60,7 @@
57
60
  "@types/winston": "^2.4.4",
58
61
  "rollup-plugin-auto-external": "^2.0.0",
59
62
  "rollup-plugin-cleanup": "^3.2.1",
63
+ "rollup-plugin-copy": "^3.5.0",
60
64
  "rollup-plugin-typescript2": "^0.34.1",
61
65
  "solc": "^0.8.19",
62
66
  "ts-node": "^10.9.1",
@@ -65,10 +69,12 @@
65
69
  "dependencies": {
66
70
  "@adobe/node-fetch-retry": "^2.2.0",
67
71
  "@aws-sdk/client-s3": "^3.329.0",
72
+ "@bandada/api-sdk": "^1.0.0-beta.1",
68
73
  "@devtion/actions": "latest",
69
74
  "@octokit/auth-oauth-app": "^5.0.5",
70
75
  "@octokit/auth-oauth-device": "^4.0.4",
71
76
  "@octokit/request": "^6.2.3",
77
+ "@semaphore-protocol/identity": "^3.15.1",
72
78
  "blakejs": "^1.2.1",
73
79
  "boxen": "^7.1.0",
74
80
  "chalk": "^5.2.0",
@@ -78,6 +84,7 @@
78
84
  "commander": "^10.0.1",
79
85
  "conf": "^11.0.1",
80
86
  "dotenv": "^16.0.3",
87
+ "ethers": "^6.9.0",
81
88
  "figlet": "^1.6.0",
82
89
  "firebase": "^9.21.0",
83
90
  "log-symbols": "^5.1.0",
@@ -90,12 +97,12 @@
90
97
  "prompts": "^2.4.2",
91
98
  "rimraf": "^5.0.0",
92
99
  "rollup": "^3.21.6",
93
- "snarkjs": "^0.6.11",
100
+ "snarkjs": "0.7.3",
94
101
  "timer-node": "^5.0.7",
95
102
  "winston": "^3.8.2"
96
103
  },
97
104
  "publishConfig": {
98
105
  "access": "public"
99
106
  },
100
- "gitHead": "253890f0a88d586c4d023c6ace7a5fd3d5085568"
107
+ "gitHead": "ff65fa7623e6793f308b61d6ad734eedf3c87e2b"
101
108
  }
@@ -8,7 +8,12 @@ import figlet from "figlet"
8
8
  import { fileURLToPath } from "url"
9
9
  import { dirname } from "path"
10
10
  import { GENERIC_ERRORS, showError } from "../lib/errors.js"
11
- import { checkLocalAccessToken, getLocalAccessToken, setLocalAccessToken } from "../lib/localConfigs.js"
11
+ import {
12
+ checkLocalAccessToken,
13
+ getLocalAccessToken,
14
+ setLocalAccessToken,
15
+ setLocalAuthMethod
16
+ } from "../lib/localConfigs.js"
12
17
  import { bootstrapCommandExecutionAndServices, signInToFirebase } from "../lib/services.js"
13
18
  import theme from "../lib/theme.js"
14
19
  import {
@@ -171,6 +176,7 @@ const auth = async () => {
171
176
  const newToken = await executeGithubDeviceFlow(String(process.env.AUTH_GITHUB_CLIENT_ID))
172
177
 
173
178
  // Store the new access token.
179
+ setLocalAuthMethod("github")
174
180
  setLocalAccessToken(newToken)
175
181
  } else spinner.succeed(`Local authentication token found\n`)
176
182
 
@@ -0,0 +1,120 @@
1
+ import { Identity } from "@semaphore-protocol/identity"
2
+
3
+ import { commonTerms } from "@devtion/actions"
4
+ import { httpsCallable } from "firebase/functions"
5
+ import { groth16 } from "snarkjs"
6
+ import { getAuth, signInWithCustomToken } from "firebase/auth"
7
+ import prompts from "prompts"
8
+ import { getLocalDirname } from "../lib/files.js"
9
+ import theme from "../lib/theme.js"
10
+ import { customSpinner } from "../lib/utils.js"
11
+ import { VerifiedBandadaResponse } from "../types/index.js"
12
+ import { showError } from "../lib/errors.js"
13
+ import { bootstrapCommandExecutionAndServices } from "../lib/services.js"
14
+ import { addMemberToGroup, isGroupMember } from "../lib/bandada.js"
15
+ import {
16
+ checkLocalBandadaIdentity,
17
+ deleteLocalAccessToken,
18
+ deleteLocalAuthMethod,
19
+ deleteLocalBandadaIdentity,
20
+ getLocalBandadaIdentity,
21
+ setLocalAccessToken,
22
+ setLocalAuthMethod,
23
+ setLocalBandadaIdentity
24
+ } from "../lib/localConfigs.js"
25
+
26
+ const { BANDADA_DASHBOARD_URL, BANDADA_GROUP_ID } = process.env
27
+
28
+ const authBandada = async () => {
29
+ try {
30
+ const { firebaseFunctions } = await bootstrapCommandExecutionAndServices()
31
+ const spinner = customSpinner(`Checking identity string for Semaphore...`, `clock`)
32
+ spinner.start()
33
+ // 1. check if _identity string exists in local storage
34
+ let identityString: string | unknown
35
+ const isIdentityStringStored = checkLocalBandadaIdentity()
36
+ if (isIdentityStringStored) {
37
+ identityString = getLocalBandadaIdentity()
38
+ spinner.succeed(`Identity seed found\n`)
39
+ } else {
40
+ spinner.warn(`Identity seed not found\n`)
41
+ // 2. generate a random _identity string and save it in local storage
42
+ const { seed } = await prompts({
43
+ type: "text",
44
+ name: "seed",
45
+ message: theme.text.bold(`Enter a secret string to use as your identity seed in Semaphore:`),
46
+ initial: false
47
+ })
48
+ identityString = seed as string
49
+ setLocalBandadaIdentity(identityString as string)
50
+ }
51
+ // 3. create a semaphore identity with _identity string as a seed
52
+ const identity = new Identity(identityString as string)
53
+
54
+ // 4. check if the user is a member of the group
55
+ console.log(`Checking Bandada membership...`)
56
+ const isMember = await isGroupMember(BANDADA_GROUP_ID, identity)
57
+ if (!isMember) {
58
+ await addMemberToGroup(BANDADA_GROUP_ID, BANDADA_DASHBOARD_URL, identity)
59
+ }
60
+
61
+ // 5. generate a proof that the user owns the commitment.
62
+ spinner.text = `Generating proof of identity...`
63
+ spinner.start()
64
+ // publicSignals = [hash(externalNullifier, identityNullifier), commitment]
65
+
66
+ const initDirectoryName = getLocalDirname()
67
+ const directoryName = initDirectoryName.includes("/src") ? "." : initDirectoryName
68
+
69
+ const { proof, publicSignals } = await groth16.fullProve(
70
+ {
71
+ identityTrapdoor: identity.trapdoor,
72
+ identityNullifier: identity.nullifier,
73
+ externalNullifier: BANDADA_GROUP_ID
74
+ },
75
+ `${directoryName}/public/mini-semaphore.wasm`,
76
+ `${directoryName}/public/mini-semaphore.zkey`
77
+ )
78
+ spinner.succeed(`Proof generated.\n`)
79
+ spinner.text = `Sending proof to verification...`
80
+ spinner.start()
81
+ // 6. send proof to a cloud function that verifies it and checks membership
82
+ const cf = httpsCallable(firebaseFunctions, commonTerms.cloudFunctionsNames.bandadaValidateProof)
83
+ const result = await cf({
84
+ proof,
85
+ publicSignals
86
+ })
87
+ const { valid, token, message } = result.data as VerifiedBandadaResponse
88
+ if (!valid) {
89
+ showError(message, true)
90
+ deleteLocalAuthMethod()
91
+ deleteLocalAccessToken()
92
+ deleteLocalBandadaIdentity()
93
+ }
94
+ spinner.succeed(`Proof verified.\n`)
95
+ spinner.text = `Authenticating...`
96
+ spinner.start()
97
+ // 7. Auth to p0tion firebase
98
+ const credentials = await signInWithCustomToken(getAuth(), token)
99
+ setLocalAuthMethod("bandada")
100
+ setLocalAccessToken(token)
101
+ spinner.succeed(`Authenticated as ${theme.text.bold(credentials.user.uid)}.`)
102
+
103
+ console.log(
104
+ `\n${theme.symbols.warning} You can always log out by running the ${theme.text.bold(
105
+ `phase2cli logout`
106
+ )} command`
107
+ )
108
+ } catch (error) {
109
+ // Delete local token.
110
+ console.log("An error crashed the process. Deleting local token and identity.")
111
+ console.error(error)
112
+ deleteLocalAuthMethod()
113
+ deleteLocalAccessToken()
114
+ deleteLocalBandadaIdentity()
115
+ }
116
+
117
+ process.exit(0)
118
+ }
119
+
120
+ export default authBandada
@@ -0,0 +1,178 @@
1
+ import open from "open"
2
+ import figlet from "figlet"
3
+ import clipboard from "clipboardy"
4
+ import fetch from "node-fetch"
5
+ import { getAuth, signInWithCustomToken } from "firebase/auth"
6
+ import { httpsCallable } from "firebase/functions"
7
+ import { commonTerms } from "@devtion/actions"
8
+ import { showError } from "../lib/errors.js"
9
+ import { bootstrapCommandExecutionAndServices } from "../lib/services.js"
10
+ import theme from "../lib/theme.js"
11
+ import { customSpinner, sleep } from "../lib/utils.js"
12
+ import { CheckNonceOfSIWEAddressResponse, OAuthDeviceCodeResponse, OAuthTokenResponse } from "../types/index.js"
13
+ import {
14
+ checkLocalAccessToken,
15
+ deleteLocalAccessToken,
16
+ deleteLocalAuthMethod,
17
+ getLocalAccessToken,
18
+ setLocalAccessToken,
19
+ setLocalAuthMethod
20
+ } from "../lib/localConfigs.js"
21
+
22
+ const showVerificationCodeAndUri = async (OAuthDeviceCode: OAuthDeviceCodeResponse) => {
23
+ // Copy code to clipboard.
24
+ let noClipboard = false
25
+ try {
26
+ clipboard.writeSync(OAuthDeviceCode.user_code)
27
+ clipboard.readSync()
28
+ } catch (error) {
29
+ noClipboard = true
30
+ }
31
+ // Display data.
32
+ console.log(
33
+ `${theme.symbols.warning} Visit ${theme.text.bold(
34
+ theme.text.underlined(OAuthDeviceCode.verification_uri)
35
+ )} on this device to generate a new token and authenticate\n`
36
+ )
37
+ console.log(theme.colors.magenta(figlet.textSync("Code is Below", { font: "ANSI Shadow" })), "\n")
38
+
39
+ const message = !noClipboard ? `has been copied to your clipboard (${theme.emojis.clipboard})` : ``
40
+ console.log(
41
+ `${theme.symbols.info} Your auth code: ${theme.text.bold(OAuthDeviceCode.user_code)} ${message} ${
42
+ theme.symbols.success
43
+ }\n`
44
+ )
45
+ const spinner = customSpinner(`Redirecting to Github...`, `clock`)
46
+ spinner.start()
47
+ await sleep(10000) // ~10s to make users able to read the CLI.
48
+ try {
49
+ // Automatically open the page (# Step 2).
50
+ await open(OAuthDeviceCode.verification_uri)
51
+ } catch (error: any) {
52
+ console.log(`${theme.symbols.info} Please authenticate via GitHub at ${OAuthDeviceCode.verification_uri}`)
53
+ }
54
+ spinner.stop()
55
+ }
56
+
57
+ /**
58
+ * Return the token to sign in to Firebase after passing the SIWE Device Flow
59
+ * @param clientId <string> - The client id of the Auth0 application.
60
+ * @param firebaseFunctions <any> - The Firebase functions instance to call the cloud function
61
+ * @returns <string> - The token to sign in to Firebase
62
+ */
63
+ const executeSIWEDeviceFlow = async (clientId: string, firebaseFunctions: any): Promise<string> => {
64
+ // Call Auth0 endpoint to request device code uri
65
+ const OAuthDeviceCode = (await fetch(`${process.env.AUTH0_APPLICATION_URL}/oauth/device/code`, {
66
+ method: "POST",
67
+ headers: { "content-type": "application/json" },
68
+ body: JSON.stringify({
69
+ client_id: clientId,
70
+ scope: "openid",
71
+ audience: `${process.env.AUTH0_APPLICATION_URL}/api/v2/`
72
+ })
73
+ }).then((_res) => _res.json())) as OAuthDeviceCodeResponse
74
+ await showVerificationCodeAndUri(OAuthDeviceCode)
75
+ // Poll Auth0 endpoint until you get token or request expires
76
+ let isSignedIn = false
77
+ let isExpired = false
78
+ let auth0Token = ""
79
+ while (!isSignedIn && !isExpired) {
80
+ // Call Auth0 endpoint to request token
81
+ const OAuthToken = (await fetch(`${process.env.AUTH0_APPLICATION_URL}/oauth/token`, {
82
+ method: "POST",
83
+ headers: { "content-type": "application/json" },
84
+ body: JSON.stringify({
85
+ client_id: clientId,
86
+ device_code: OAuthDeviceCode.device_code,
87
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code"
88
+ })
89
+ }).then((_res) => _res.json())) as OAuthTokenResponse
90
+ if (OAuthToken.error) {
91
+ if (OAuthToken.error === "authorization_pending") {
92
+ // Wait for the user to sign in
93
+ await sleep(OAuthDeviceCode.interval * 1000)
94
+ } else if (OAuthToken.error === "slow_down") {
95
+ // Wait for the user to sign in
96
+ await sleep(OAuthDeviceCode.interval * 1000 * 2)
97
+ } else if (OAuthToken.error === "expired_token") {
98
+ // The user didn't sign in on time
99
+ isExpired = true
100
+ }
101
+ } else {
102
+ // The user signed in
103
+ isSignedIn = true
104
+ auth0Token = OAuthToken.access_token
105
+ }
106
+ }
107
+ // Send token to cloud function to check nonce, create user and retrieve token
108
+ const cf = httpsCallable(firebaseFunctions, commonTerms.cloudFunctionsNames.checkNonceOfSIWEAddress)
109
+ const result = await cf({
110
+ auth0Token
111
+ })
112
+ const { token, valid, message } = result.data as CheckNonceOfSIWEAddressResponse
113
+ if (!valid) {
114
+ showError(message, true)
115
+ deleteLocalAuthMethod()
116
+ deleteLocalAccessToken()
117
+ }
118
+ return token
119
+ }
120
+
121
+ /**
122
+ * Auth command using Sign In With Ethereum
123
+ * @notice The auth command allows a user to make the association of their Ethereum account with the CLI by leveraging SIWE as an authentication mechanism.
124
+ * @dev Under the hood, the command handles a manual Device Flow following the guidelines in the SIWE documentation.
125
+ */
126
+ const authSIWE = async () => {
127
+ try {
128
+ const { firebaseFunctions } = await bootstrapCommandExecutionAndServices()
129
+ // Console more context for the user.
130
+ console.log(
131
+ `${theme.symbols.info} ${theme.text.bold(
132
+ `You are about to authenticate on this CLI using your Ethereum address (device flow - OAuth 2.0 mechanism).\n${theme.symbols.warning} Please, note that only a Sign-in With Ethereum signature will be required`
133
+ )}\n`
134
+ )
135
+ const spinner = customSpinner(`Checking authentication token...`, `clock`)
136
+ spinner.start()
137
+ await sleep(5000)
138
+
139
+ // Manage OAuth Github or SIWE token.
140
+ const isLocalTokenStored = checkLocalAccessToken()
141
+
142
+ if (!isLocalTokenStored) {
143
+ spinner.fail(`No local authentication token found\n`)
144
+
145
+ // Generate a new access token using Github Device Flow (OAuth 2.0).
146
+ const newToken = await executeSIWEDeviceFlow(String(process.env.AUTH_SIWE_CLIENT_ID), firebaseFunctions)
147
+
148
+ // Store the new access token.
149
+ setLocalAuthMethod("siwe")
150
+ setLocalAccessToken(newToken)
151
+ } else spinner.succeed(`Local authentication token found\n`)
152
+
153
+ // Get access token from local store.
154
+ const token = String(getLocalAccessToken())
155
+
156
+ spinner.text = `Authenticating...`
157
+ spinner.start()
158
+
159
+ // Exchange token for credential.
160
+ const credentials = await signInWithCustomToken(getAuth(), token)
161
+ spinner.succeed(`Authenticated as ${theme.text.bold(credentials.user.uid)}.`)
162
+
163
+ console.log(
164
+ `\n${theme.symbols.warning} You can always log out by running the ${theme.text.bold(
165
+ `phase2cli logout`
166
+ )} command`
167
+ )
168
+ process.exit(0)
169
+ } catch (error) {
170
+ // Delete local token.
171
+ console.log("An error crashed the process. Deleting local token and identity.")
172
+ console.error(error)
173
+ deleteLocalAuthMethod()
174
+ deleteLocalAccessToken()
175
+ }
176
+ }
177
+
178
+ export default authSIWE
@@ -0,0 +1,20 @@
1
+ import { Command } from "commander"
2
+ import listParticipants from "./listParticipants.js"
3
+
4
+ const setCeremonyCommands = (program: Command) => {
5
+ const ceremony = program.command("ceremony").description("manage ceremonies")
6
+
7
+ ceremony
8
+ .command("participants")
9
+ .description("retrieve participants list of a ceremony")
10
+ .requiredOption(
11
+ "-c, --ceremony <string>",
12
+ "the prefix of the ceremony you want to retrieve information about",
13
+ ""
14
+ )
15
+ .action(listParticipants)
16
+
17
+ return ceremony
18
+ }
19
+
20
+ export default setCeremonyCommands
@@ -0,0 +1,30 @@
1
+ import { collection, doc, getDocs } from "firebase/firestore"
2
+ import { commonTerms, getAllCeremonies } from "@devtion/actions"
3
+ import { bootstrapCommandExecutionAndServices } from "../../lib/services.js"
4
+ import { showError } from "../../lib/errors.js"
5
+ import { promptForCeremonySelection } from "../../lib/prompts.js"
6
+
7
+ const listParticipants = async () => {
8
+ try {
9
+ const { firestoreDatabase } = await bootstrapCommandExecutionAndServices()
10
+
11
+ const allCeremonies = await getAllCeremonies(firestoreDatabase)
12
+ const selectedCeremony = await promptForCeremonySelection(allCeremonies, true)
13
+
14
+ const docRef = doc(firestoreDatabase, commonTerms.collections.ceremonies.name, selectedCeremony.id)
15
+ const participantsRef = collection(docRef, "participants")
16
+ const participantsSnapshot = await getDocs(participantsRef)
17
+ const participants = participantsSnapshot.docs.map((participantDoc) => participantDoc.data().userId)
18
+ console.log(participants)
19
+
20
+ /* const usersRef = collection(firestoreDatabase, "users")
21
+ const usersSnapshot = await getDocs(usersRef)
22
+ const users = usersSnapshot.docs.map((userDoc) => userDoc.data())
23
+ console.log(users) */
24
+ } catch (err: any) {
25
+ showError(`Something went wrong: ${err.toString()}`, true)
26
+ }
27
+ process.exit(0)
28
+ }
29
+
30
+ export default listParticipants
@@ -41,7 +41,7 @@ import {
41
41
  } from "../lib/utils.js"
42
42
  import { COMMAND_ERRORS, showError } from "../lib/errors.js"
43
43
  import { authWithToken, bootstrapCommandExecutionAndServices, checkAuth } from "../lib/services.js"
44
- import { getAttestationLocalFilePath, localPaths } from "../lib/localConfigs.js"
44
+ import { getAttestationLocalFilePath, getLocalAuthMethod, localPaths } from "../lib/localConfigs.js"
45
45
  import theme from "../lib/theme.js"
46
46
  import { checkAndMakeNewDirectoryIfNonexistent, writeFile } from "../lib/files.js"
47
47
 
@@ -281,12 +281,12 @@ export const handleDiskSpaceRequirementForNextContribution = async (
281
281
  )} since is based on the aggregate free memory on your disks but some may not be detected!\n`
282
282
  )
283
283
 
284
- const { confirmation } = await askForConfirmation(
284
+ const { confirmationEnoughMemory } = await askForConfirmation(
285
285
  `Please, we kindly ask you to continue with the contribution if you have noticed the estimate is wrong and you have enough memory in your machine`,
286
286
  "Continue",
287
287
  "Exit"
288
288
  )
289
- wannaContributeOrHaveEnoughMemory = !!confirmation
289
+ wannaContributeOrHaveEnoughMemory = !!confirmationEnoughMemory
290
290
 
291
291
  if (circuitSequencePosition > 1) {
292
292
  console.log(
@@ -419,14 +419,19 @@ export const handlePublicAttestation = async (
419
419
 
420
420
  await sleep(1000) // workaround for file descriptor unexpected close.
421
421
 
422
- const gistUrl = await publishGist(participantAccessToken, publicAttestation, ceremonyName, ceremonyPrefix)
423
-
424
- console.log(
425
- `\n${theme.symbols.info} Your public attestation has been successfully posted as Github Gist (${theme.text.bold(
426
- theme.text.underlined(gistUrl)
427
- )})`
428
- )
422
+ let gistUrl = ""
423
+ const isGithub = getLocalAuthMethod() === "github"
424
+ if (isGithub) {
425
+ gistUrl = await publishGist(participantAccessToken, publicAttestation, ceremonyName, ceremonyPrefix)
429
426
 
427
+ console.log(
428
+ `\n${
429
+ theme.symbols.info
430
+ } Your public attestation has been successfully posted as Github Gist (${theme.text.bold(
431
+ theme.text.underlined(gistUrl)
432
+ )})`
433
+ )
434
+ }
430
435
  // Prepare a ready-to-share tweet.
431
436
  await handleTweetGeneration(ceremonyName, gistUrl)
432
437
  }
@@ -952,7 +957,7 @@ const contribute = async (opt: any) => {
952
957
  const userData = userDoc.data()
953
958
  if (!userData) {
954
959
  spinner.fail(
955
- `Unfortunately we could not find a user document with your information. This likely means that you did not pass the GitHub reputation checks and therefore are not elegible to contribute to any ceremony. If you believe you pass the requirements, it might be possible that your profile is private and we were not able to fetch your real statistics, in this case please consider making your profile public for the duration of the contribution. Please contact the coordinator if you believe this to be an error.`
960
+ `Unfortunately we could not find a user document with your information. This likely means that you did not pass the GitHub reputation checks and therefore are not eligible to contribute to any ceremony. If you believe you pass the requirements, it might be possible that your profile is private and we were not able to fetch your real statistics, in this case please consider making your profile public for the duration of the contribution. Please contact the coordinator if you believe this to be an error.`
956
961
  )
957
962
  process.exit(0)
958
963
  }
@@ -74,7 +74,7 @@ export const handleVerificationKey = async (
74
74
  // Write the verification key locally.
75
75
  writeLocalJsonFile(verificationKeyLocalFilePath, vKey)
76
76
 
77
- await sleep(3000) // workaound for file descriptor.
77
+ await sleep(3000) // workaround for file descriptor.
78
78
 
79
79
  // Upload verification key to storage.
80
80
  await multiPartUpload(
@@ -122,7 +122,7 @@ export const handleVerifierSmartContract = async (
122
122
  // Write the verification key locally.
123
123
  writeFile(verifierContractLocalFilePath, verifierCode)
124
124
 
125
- await sleep(3000) // workaound for file descriptor.
125
+ await sleep(3000) // workaround for file descriptor.
126
126
 
127
127
  // Upload verifier smart contract to storage.
128
128
  await multiPartUpload(
@@ -177,7 +177,7 @@ export const handleCircuitFinalization = async (
177
177
  circuitsLength
178
178
  )
179
179
 
180
- await sleep(2000) // workaound for descriptors.
180
+ await sleep(2000) // workaround for descriptors.
181
181
 
182
182
  // Extract data.
183
183
  const { prefix: circuitPrefix } = circuit.data
@@ -1,5 +1,7 @@
1
1
  export { default as setup } from "./setup.js"
2
2
  export { default as auth } from "./auth.js"
3
+ export { default as authBandada } from "./authBandada.js"
4
+ export { default as authSIWE } from "./authSIWE.js"
3
5
  export { default as contribute } from "./contribute.js"
4
6
  export { default as observe } from "./observe.js"
5
7
  export { default as finalize } from "./finalize.js"
@@ -6,7 +6,7 @@ import { showError } from "../lib/errors.js"
6
6
  import { askForConfirmation } from "../lib/prompts.js"
7
7
  import { customSpinner, sleep, terminate } from "../lib/utils.js"
8
8
  import theme from "../lib/theme.js"
9
- import { deleteLocalAccessToken } from "../lib/localConfigs.js"
9
+ import { deleteLocalAccessToken, deleteLocalAuthMethod, deleteLocalBandadaIdentity } from "../lib/localConfigs.js"
10
10
 
11
11
  /**
12
12
  * Logout command.
@@ -52,7 +52,9 @@ const logout = async () => {
52
52
  await signOut(auth)
53
53
 
54
54
  // Delete local token.
55
+ deleteLocalAuthMethod()
55
56
  deleteLocalAccessToken()
57
+ deleteLocalBandadaIdentity()
56
58
 
57
59
  await sleep(3000) // ~3s.
58
60