@devtion/devcli 0.0.0-5d170d3 → 0.0.0-67a4629
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 +3 -1
- package/dist/.env +10 -3
- package/dist/index.js +315 -104
- package/dist/public/mini-semaphore.wasm +0 -0
- package/dist/public/mini-semaphore.zkey +0 -0
- package/dist/types/commands/authBandada.d.ts +2 -0
- package/dist/types/commands/ceremony/index.d.ts +3 -0
- package/dist/types/commands/ceremony/listParticipants.d.ts +2 -0
- package/dist/types/commands/contribute.d.ts +1 -1
- package/dist/types/commands/finalize.d.ts +4 -3
- package/dist/types/commands/index.d.ts +1 -0
- package/dist/types/commands/observe.d.ts +1 -1
- package/dist/types/commands/setup.d.ts +2 -2
- package/dist/types/lib/bandada.d.ts +6 -0
- package/dist/types/lib/files.d.ts +1 -0
- package/dist/types/lib/localConfigs.d.ts +19 -0
- package/dist/types/lib/prompts.d.ts +6 -6
- package/dist/types/lib/utils.d.ts +3 -2
- package/dist/types/types/index.d.ts +12 -0
- package/package.json +11 -4
- package/src/commands/auth.ts +21 -7
- package/src/commands/authBandada.ts +110 -0
- package/src/commands/ceremony/index.ts +20 -0
- package/src/commands/ceremony/listParticipants.ts +30 -0
- package/src/commands/contribute.ts +25 -17
- package/src/commands/finalize.ts +22 -13
- package/src/commands/index.ts +2 -1
- package/src/commands/listCeremonies.ts +2 -3
- package/src/commands/logout.ts +2 -1
- package/src/commands/observe.ts +3 -3
- package/src/commands/setup.ts +56 -45
- package/src/commands/validate.ts +2 -3
- package/src/index.ts +30 -13
- package/src/lib/bandada.ts +51 -0
- package/src/lib/errors.ts +1 -1
- package/src/lib/localConfigs.ts +28 -1
- package/src/lib/prompts.ts +20 -20
- package/src/lib/services.ts +27 -16
- package/src/lib/utils.ts +45 -10
- package/src/types/index.ts +13 -0
|
Binary file
|
|
Binary file
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Contribution, ContributionValidity, FirebaseDocumentInfo } from "@
|
|
2
|
+
import { Contribution, ContributionValidity, FirebaseDocumentInfo } from "@devtion/actions";
|
|
3
3
|
import { DocumentSnapshot, DocumentData, Firestore } from "firebase/firestore";
|
|
4
4
|
import { Functions } from "firebase/functions";
|
|
5
5
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { FirebaseDocumentInfo } from "@
|
|
2
|
+
import { FirebaseDocumentInfo } from "@devtion/actions";
|
|
3
3
|
import { Functions } from "firebase/functions";
|
|
4
4
|
import { Firestore } from "firebase/firestore";
|
|
5
5
|
/**
|
|
@@ -36,8 +36,9 @@ export declare const handleVerifierSmartContract: (cloudFunctions: Functions, bu
|
|
|
36
36
|
* @param participant <FirebaseDocumentInfo> - the Firestore document of the participant (coordinator).
|
|
37
37
|
* @param beacon <string> - the value used to compute the final contribution while finalizing the ceremony.
|
|
38
38
|
* @param coordinatorIdentifier <string> - the identifier of the coordinator.
|
|
39
|
+
* @param circuitsLength <number> - the number of circuits in the ceremony.
|
|
39
40
|
*/
|
|
40
|
-
export declare const handleCircuitFinalization: (cloudFunctions: Functions, firestoreDatabase: Firestore, ceremony: FirebaseDocumentInfo, circuit: FirebaseDocumentInfo, participant: FirebaseDocumentInfo, beacon: string, coordinatorIdentifier: string) => Promise<void>;
|
|
41
|
+
export declare const handleCircuitFinalization: (cloudFunctions: Functions, firestoreDatabase: Firestore, ceremony: FirebaseDocumentInfo, circuit: FirebaseDocumentInfo, participant: FirebaseDocumentInfo, beacon: string, coordinatorIdentifier: string, circuitsLength: number) => Promise<void>;
|
|
41
42
|
/**
|
|
42
43
|
* Finalize command.
|
|
43
44
|
* @notice The finalize command allows a coordinator to finalize a Trusted Setup Phase 2 ceremony by providing the final beacon,
|
|
@@ -47,5 +48,5 @@ export declare const handleCircuitFinalization: (cloudFunctions: Functions, fire
|
|
|
47
48
|
* @dev For proper execution, the command requires the coordinator to be authenticated with a GitHub account (run auth command first) in order to
|
|
48
49
|
* handle sybil-resistance and connect to GitHub APIs to publish the gist containing the final public attestation.
|
|
49
50
|
*/
|
|
50
|
-
declare const finalize: () => Promise<void>;
|
|
51
|
+
declare const finalize: (opt: any) => Promise<void>;
|
|
51
52
|
export default finalize;
|
|
@@ -1,5 +1,6 @@
|
|
|
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";
|
|
3
4
|
export { default as contribute } from "./contribute.js";
|
|
4
5
|
export { default as observe } from "./observe.js";
|
|
5
6
|
export { default as finalize } from "./finalize.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Functions } from "firebase/functions";
|
|
3
|
-
import { CeremonyTimeoutType, CircomCompilerData, CircuitInputData, CeremonyInputData, CircuitDocument } from "@
|
|
3
|
+
import { CeremonyTimeoutType, CircomCompilerData, CircuitInputData, CeremonyInputData, CircuitDocument } from "@devtion/actions";
|
|
4
4
|
/**
|
|
5
5
|
* Handle whatever is needed to obtain the input data for a circuit that the coordinator would like to add to the ceremony.
|
|
6
6
|
* @param choosenCircuitFilename <string> - the name of the circuit to add.
|
|
@@ -39,7 +39,7 @@ export declare const checkAndDownloadSmallestPowersOfTau: (powers: string, ptauC
|
|
|
39
39
|
* number of powers greater than or equal to the powers needed by the zKey), the coordinator will be asked
|
|
40
40
|
* to provide a number of powers manually, ranging from the smallest possible to the largest.
|
|
41
41
|
* @param neededPowers <number> - the smallest amount of powers needed by the zKey.
|
|
42
|
-
* @returns Promise<string, string> - the information about the
|
|
42
|
+
* @returns Promise<string, string> - the information about the chosen Powers of Tau file for the pre-computed zKey
|
|
43
43
|
* along with related powers.
|
|
44
44
|
*/
|
|
45
45
|
export declare const handlePreComputedZkeyPowersOfTauSelection: (neededPowers: number) => Promise<{
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { GroupResponse } from "@bandada/api-sdk";
|
|
2
|
+
import { Identity } from "@semaphore-protocol/identity";
|
|
3
|
+
export declare const getGroup: (groupId: string) => Promise<GroupResponse | null>;
|
|
4
|
+
export declare const getMembersOfGroup: (groupId: string) => Promise<string[] | null>;
|
|
5
|
+
export declare const addMemberToGroup: (groupId: string, dashboardUrl: string, identity: Identity) => Promise<void>;
|
|
6
|
+
export declare const isGroupMember: (groupId: string, identity: Identity) => Promise<boolean>;
|
|
@@ -35,6 +35,25 @@ 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;
|
|
38
57
|
/**
|
|
39
58
|
* Get the complete local file path.
|
|
40
59
|
* @param cwd <string> - the current working directory path.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Answers } from "prompts";
|
|
2
2
|
import { Firestore } from "firebase/firestore";
|
|
3
|
-
import { CeremonyInputData, FirebaseDocumentInfo, CircomCompilerData, CircuitInputData, CeremonyTimeoutType, DiskTypeForVM } from "@
|
|
3
|
+
import { CeremonyInputData, FirebaseDocumentInfo, CircomCompilerData, CircuitInputData, CeremonyTimeoutType, DiskTypeForVM } from "@devtion/actions";
|
|
4
4
|
/**
|
|
5
5
|
* Ask a binary (yes/no or true/false) customizable question.
|
|
6
6
|
* @param question <string> - the question to be answered.
|
|
@@ -24,14 +24,14 @@ export declare const promptCircomCompiler: () => Promise<CircomCompilerData>;
|
|
|
24
24
|
* Shows a list of circuits for a single option selection.
|
|
25
25
|
* @dev the circuit names are derived from local R1CS files.
|
|
26
26
|
* @param options <Array<string>> - an array of circuits names.
|
|
27
|
-
* @returns Promise<string> - the name of the
|
|
27
|
+
* @returns Promise<string> - the name of the chosen circuit.
|
|
28
28
|
*/
|
|
29
29
|
export declare const promptCircuitSelector: (options: Array<string>) => Promise<string>;
|
|
30
30
|
/**
|
|
31
31
|
* Shows a list of standard EC2 VM instance types for a single option selection.
|
|
32
32
|
* @notice the suggested VM configuration type is calculated based on circuit constraint size.
|
|
33
33
|
* @param constraintSize <number> - the amount of circuit constraints
|
|
34
|
-
* @returns Promise<string> - the name of the
|
|
34
|
+
* @returns Promise<string> - the name of the chosen VM type.
|
|
35
35
|
*/
|
|
36
36
|
export declare const promptVMTypeSelector: (constraintSize: any) => Promise<string>;
|
|
37
37
|
/**
|
|
@@ -42,7 +42,7 @@ export declare const promptVMDiskTypeSelector: () => Promise<DiskTypeForVM>;
|
|
|
42
42
|
/**
|
|
43
43
|
* Show a series of questions about the circuits.
|
|
44
44
|
* @param constraintSize <number> - the amount of circuit constraints.
|
|
45
|
-
* @param timeoutMechanismType <CeremonyTimeoutType> - the
|
|
45
|
+
* @param timeoutMechanismType <CeremonyTimeoutType> - the chosen timeout mechanism type for the ceremony.
|
|
46
46
|
* @param needPromptCircomCompiler <boolean> - a boolean value indicating if the questions related to the Circom compiler version and commit hash must be asked.
|
|
47
47
|
* @param enforceVM <boolean> - a boolean value indicating if the contribution verification could be supported by VM-only approach or not.
|
|
48
48
|
* @returns Promise<Array<Circuit>> - circuit info prompted by the coordinator.
|
|
@@ -67,7 +67,7 @@ export declare const promptCircuitAddition: () => Promise<boolean>;
|
|
|
67
67
|
* Shows a list of pre-computed zKeys for a single option selection.
|
|
68
68
|
* @dev the names are derived from local zKeys files.
|
|
69
69
|
* @param options <Array<string>> - an array of pre-computed zKeys names.
|
|
70
|
-
* @returns Promise<string> - the name of the
|
|
70
|
+
* @returns Promise<string> - the name of the chosen pre-computed zKey.
|
|
71
71
|
*/
|
|
72
72
|
export declare const promptPreComputedZkeySelector: (options: Array<string>) => Promise<string>;
|
|
73
73
|
/**
|
|
@@ -80,7 +80,7 @@ export declare const promptNeededPowersForCircuit: (suggestedSmallestNeededPower
|
|
|
80
80
|
* Shows a list of PoT files for a single option selection.
|
|
81
81
|
* @dev the names are derived from local PoT files.
|
|
82
82
|
* @param options <Array<string>> - an array of PoT file names.
|
|
83
|
-
* @returns Promise<string> - the name of the
|
|
83
|
+
* @returns Promise<string> - the name of the chosen PoT.
|
|
84
84
|
*/
|
|
85
85
|
export declare const promptPotSelector: (options: Array<string>) => Promise<string>;
|
|
86
86
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FirebaseDocumentInfo } from "@
|
|
1
|
+
import { FirebaseDocumentInfo } from "@devtion/actions";
|
|
2
2
|
import { OAuthCredential } from "firebase/auth";
|
|
3
3
|
import { DocumentData, Firestore } from "firebase/firestore";
|
|
4
4
|
import { Functions } from "firebase/functions";
|
|
@@ -154,5 +154,6 @@ export declare const getLatestUpdatesFromParticipant: (firestoreDatabase: Firest
|
|
|
154
154
|
* @param entropyOrBeaconHash <string> - the entropy or beacon hash (only when finalizing) for the contribution.
|
|
155
155
|
* @param contributorOrCoordinatorIdentifier <string> - the identifier of the contributor or coordinator (only when finalizing).
|
|
156
156
|
* @param isFinalizing <boolean> - flag to discriminate between ceremony finalization (true) and contribution (false).
|
|
157
|
+
* @param circuitsLength <number> - the total number of circuits in the ceremony.
|
|
157
158
|
*/
|
|
158
|
-
export declare const handleStartOrResumeContribution: (cloudFunctions: Functions, firestoreDatabase: Firestore, ceremony: FirebaseDocumentInfo, circuit: FirebaseDocumentInfo, participant: FirebaseDocumentInfo, entropyOrBeaconHash: any, contributorOrCoordinatorIdentifier: string, isFinalizing: boolean) => Promise<void>;
|
|
159
|
+
export declare const handleStartOrResumeContribution: (cloudFunctions: Functions, firestoreDatabase: Firestore, ceremony: FirebaseDocumentInfo, circuit: FirebaseDocumentInfo, participant: FirebaseDocumentInfo, entropyOrBeaconHash: any, contributorOrCoordinatorIdentifier: string, isFinalizing: boolean, circuitsLength: number) => Promise<void>;
|
|
@@ -63,3 +63,15 @@ 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
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devtion/devcli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.0-
|
|
4
|
+
"version": "0.0.0-67a4629",
|
|
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,13 @@
|
|
|
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:bandada": "yarn start auth-bandada",
|
|
37
38
|
"contribute": "yarn start contribute",
|
|
38
39
|
"clean": "yarn start clean",
|
|
39
40
|
"list": "yarn start list",
|
|
40
41
|
"logout": "yarn start logout",
|
|
41
42
|
"validate": "yarn start validate",
|
|
43
|
+
"ceremony:participants": "yarn start ceremony participants",
|
|
42
44
|
"coordinate:setup": "yarn start coordinate setup",
|
|
43
45
|
"coordinate:observe": "yarn start coordinate observe",
|
|
44
46
|
"coordinate:finalize": "yarn start coordinate finalize",
|
|
@@ -57,6 +59,7 @@
|
|
|
57
59
|
"@types/winston": "^2.4.4",
|
|
58
60
|
"rollup-plugin-auto-external": "^2.0.0",
|
|
59
61
|
"rollup-plugin-cleanup": "^3.2.1",
|
|
62
|
+
"rollup-plugin-copy": "^3.5.0",
|
|
60
63
|
"rollup-plugin-typescript2": "^0.34.1",
|
|
61
64
|
"solc": "^0.8.19",
|
|
62
65
|
"ts-node": "^10.9.1",
|
|
@@ -64,10 +67,13 @@
|
|
|
64
67
|
},
|
|
65
68
|
"dependencies": {
|
|
66
69
|
"@adobe/node-fetch-retry": "^2.2.0",
|
|
70
|
+
"@aws-sdk/client-s3": "^3.329.0",
|
|
71
|
+
"@bandada/api-sdk": "^1.0.0-beta.1",
|
|
72
|
+
"@devtion/actions": "latest",
|
|
67
73
|
"@octokit/auth-oauth-app": "^5.0.5",
|
|
68
74
|
"@octokit/auth-oauth-device": "^4.0.4",
|
|
69
75
|
"@octokit/request": "^6.2.3",
|
|
70
|
-
"@
|
|
76
|
+
"@semaphore-protocol/identity": "^3.15.1",
|
|
71
77
|
"blakejs": "^1.2.1",
|
|
72
78
|
"boxen": "^7.1.0",
|
|
73
79
|
"chalk": "^5.2.0",
|
|
@@ -77,6 +83,7 @@
|
|
|
77
83
|
"commander": "^10.0.1",
|
|
78
84
|
"conf": "^11.0.1",
|
|
79
85
|
"dotenv": "^16.0.3",
|
|
86
|
+
"ethers": "^6.9.0",
|
|
80
87
|
"figlet": "^1.6.0",
|
|
81
88
|
"firebase": "^9.21.0",
|
|
82
89
|
"log-symbols": "^5.1.0",
|
|
@@ -89,12 +96,12 @@
|
|
|
89
96
|
"prompts": "^2.4.2",
|
|
90
97
|
"rimraf": "^5.0.0",
|
|
91
98
|
"rollup": "^3.21.6",
|
|
92
|
-
"snarkjs": "
|
|
99
|
+
"snarkjs": "0.7.3",
|
|
93
100
|
"timer-node": "^5.0.7",
|
|
94
101
|
"winston": "^3.8.2"
|
|
95
102
|
},
|
|
96
103
|
"publishConfig": {
|
|
97
104
|
"access": "public"
|
|
98
105
|
},
|
|
99
|
-
"gitHead": "
|
|
106
|
+
"gitHead": "74b2b41e243efd4386fd93aba889348ce95e35a7"
|
|
100
107
|
}
|
package/src/commands/auth.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Verification } from "@octokit/auth-oauth-device/dist-types/types.js"
|
|
|
4
4
|
import clipboard from "clipboardy"
|
|
5
5
|
import dotenv from "dotenv"
|
|
6
6
|
import open from "open"
|
|
7
|
+
import figlet from "figlet"
|
|
7
8
|
import { fileURLToPath } from "url"
|
|
8
9
|
import { dirname } from "path"
|
|
9
10
|
import { GENERIC_ERRORS, showError } from "../lib/errors.js"
|
|
@@ -62,19 +63,28 @@ export const expirationCountdownForGithubOAuth = (expirationInSeconds: number) =
|
|
|
62
63
|
*/
|
|
63
64
|
export const onVerification = async (verification: Verification): Promise<void> => {
|
|
64
65
|
// Copy code to clipboard.
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
let noClipboard = false
|
|
67
|
+
try {
|
|
68
|
+
clipboard.writeSync(verification.user_code)
|
|
69
|
+
clipboard.readSync()
|
|
70
|
+
} catch (error) {
|
|
71
|
+
noClipboard = true
|
|
72
|
+
}
|
|
67
73
|
|
|
68
74
|
// Display data.
|
|
69
75
|
console.log(
|
|
70
76
|
`${theme.symbols.warning} Visit ${theme.text.bold(
|
|
71
77
|
theme.text.underlined(verification.verification_uri)
|
|
72
|
-
)} on this device to generate a new token and authenticate`
|
|
78
|
+
)} on this device to generate a new token and authenticate\n`
|
|
73
79
|
)
|
|
80
|
+
|
|
81
|
+
console.log(theme.colors.magenta(figlet.textSync("Code is Below", { font: "ANSI Shadow" })), "\n")
|
|
82
|
+
|
|
83
|
+
const message = !noClipboard ? `has been copied to your clipboard (${theme.emojis.clipboard})` : ``
|
|
74
84
|
console.log(
|
|
75
|
-
`${theme.symbols.info} Your auth code: ${theme.text.bold(verification.user_code)}
|
|
85
|
+
`${theme.symbols.info} Your auth code: ${theme.text.bold(verification.user_code)} ${message} ${
|
|
76
86
|
theme.symbols.success
|
|
77
|
-
}
|
|
87
|
+
}\n`
|
|
78
88
|
)
|
|
79
89
|
|
|
80
90
|
const spinner = customSpinner(`Redirecting to Github...`, `clock`)
|
|
@@ -82,8 +92,12 @@ export const onVerification = async (verification: Verification): Promise<void>
|
|
|
82
92
|
|
|
83
93
|
await sleep(10000) // ~10s to make users able to read the CLI.
|
|
84
94
|
|
|
85
|
-
|
|
86
|
-
|
|
95
|
+
try {
|
|
96
|
+
// Automatically open the page (# Step 2).
|
|
97
|
+
await open(verification.verification_uri)
|
|
98
|
+
} catch (error: any) {
|
|
99
|
+
console.log(`${theme.symbols.info} Please authenticate via GitHub at ${verification.verification_uri}`)
|
|
100
|
+
}
|
|
87
101
|
|
|
88
102
|
spinner.stop()
|
|
89
103
|
|
|
@@ -0,0 +1,110 @@
|
|
|
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 { dirname } from "path"
|
|
7
|
+
import { getAuth, signInWithCustomToken } from "firebase/auth"
|
|
8
|
+
import prompts from "prompts"
|
|
9
|
+
import { fileURLToPath } from "url"
|
|
10
|
+
import theme from "../lib/theme.js"
|
|
11
|
+
import { customSpinner } from "../lib/utils.js"
|
|
12
|
+
import { VerifiedBandadaResponse } from "../types/index.js"
|
|
13
|
+
import { showError } from "../lib/errors.js"
|
|
14
|
+
import { bootstrapCommandExecutionAndServices } from "../lib/services.js"
|
|
15
|
+
import { addMemberToGroup, isGroupMember } from "../lib/bandada.js"
|
|
16
|
+
import {
|
|
17
|
+
checkLocalBandadaIdentity,
|
|
18
|
+
deleteLocalAccessToken,
|
|
19
|
+
deleteLocalBandadaIdentity,
|
|
20
|
+
getLocalBandadaIdentity,
|
|
21
|
+
setLocalAccessToken,
|
|
22
|
+
setLocalBandadaIdentity
|
|
23
|
+
} from "../lib/localConfigs.js"
|
|
24
|
+
|
|
25
|
+
const { BANDADA_DASHBOARD_URL, BANDADA_GROUP_ID } = process.env
|
|
26
|
+
|
|
27
|
+
const authBandada = async () => {
|
|
28
|
+
try {
|
|
29
|
+
const { firebaseFunctions } = await bootstrapCommandExecutionAndServices()
|
|
30
|
+
const spinner = customSpinner(`Checking identity string for Semaphore...`, `clock`)
|
|
31
|
+
spinner.start()
|
|
32
|
+
// 1. check if _identity string exists in local storage
|
|
33
|
+
let identityString: string | unknown
|
|
34
|
+
const isIdentityStringStored = checkLocalBandadaIdentity()
|
|
35
|
+
if (isIdentityStringStored) {
|
|
36
|
+
identityString = getLocalBandadaIdentity()
|
|
37
|
+
spinner.succeed(`Identity seed found\n`)
|
|
38
|
+
} else {
|
|
39
|
+
spinner.warn(`Identity seed not found\n`)
|
|
40
|
+
// 2. generate a random _identity string and save it in local storage
|
|
41
|
+
const { seed } = await prompts({
|
|
42
|
+
type: "text",
|
|
43
|
+
name: "seed",
|
|
44
|
+
message: theme.text.bold(`Enter a secret string to use as your identity seed in Semaphore:`),
|
|
45
|
+
initial: false
|
|
46
|
+
})
|
|
47
|
+
identityString = seed as string
|
|
48
|
+
setLocalBandadaIdentity(identityString as string)
|
|
49
|
+
}
|
|
50
|
+
// 3. create a semaphore identity with _identity string as a seed
|
|
51
|
+
const identity = new Identity(identityString as string)
|
|
52
|
+
|
|
53
|
+
// 4. check if the user is a member of the group
|
|
54
|
+
console.log(`Checking Bandada membership...`)
|
|
55
|
+
const isMember = await isGroupMember(BANDADA_GROUP_ID, identity)
|
|
56
|
+
if (!isMember) {
|
|
57
|
+
await addMemberToGroup(BANDADA_GROUP_ID, BANDADA_DASHBOARD_URL, identity)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 5. generate a proof that the user owns the commitment.
|
|
61
|
+
spinner.text = `Generating proof of identity...`
|
|
62
|
+
spinner.start()
|
|
63
|
+
// publicSignals = [hash(externalNullifier, identityNullifier), commitment]
|
|
64
|
+
const { proof, publicSignals } = await groth16.fullProve(
|
|
65
|
+
{
|
|
66
|
+
identityTrapdoor: identity.trapdoor,
|
|
67
|
+
identityNullifier: identity.nullifier,
|
|
68
|
+
externalNullifier: BANDADA_GROUP_ID
|
|
69
|
+
},
|
|
70
|
+
`${dirname(fileURLToPath(import.meta.url))}/public/mini-semaphore.wasm`,
|
|
71
|
+
`${dirname(fileURLToPath(import.meta.url))}/public/mini-semaphore.zkey`
|
|
72
|
+
)
|
|
73
|
+
spinner.succeed(`Proof generated.\n`)
|
|
74
|
+
spinner.text = `Sending proof to verification...`
|
|
75
|
+
spinner.start()
|
|
76
|
+
// 6. send proof to a cloud function that verifies it and checks membership
|
|
77
|
+
const cf = httpsCallable(firebaseFunctions, commonTerms.cloudFunctionsNames.bandadaValidateProof)
|
|
78
|
+
const result = await cf({
|
|
79
|
+
proof,
|
|
80
|
+
publicSignals
|
|
81
|
+
})
|
|
82
|
+
const { valid, token, message } = result.data as VerifiedBandadaResponse
|
|
83
|
+
if (!valid) {
|
|
84
|
+
showError(message, true)
|
|
85
|
+
}
|
|
86
|
+
spinner.succeed(`Proof verified.\n`)
|
|
87
|
+
spinner.text = `Authenticating...`
|
|
88
|
+
spinner.start()
|
|
89
|
+
// 7. Auth to p0tion firebase
|
|
90
|
+
const userCredentials = await signInWithCustomToken(getAuth(), token)
|
|
91
|
+
setLocalAccessToken(token)
|
|
92
|
+
spinner.succeed(`Authenticated as ${theme.text.bold(userCredentials.user.uid)}.`)
|
|
93
|
+
|
|
94
|
+
console.log(
|
|
95
|
+
`\n${theme.symbols.warning} You can always log out by running the ${theme.text.bold(
|
|
96
|
+
`phase2cli logout`
|
|
97
|
+
)} command`
|
|
98
|
+
)
|
|
99
|
+
} catch (error) {
|
|
100
|
+
// Delete local token.
|
|
101
|
+
console.log("An error crashed the process. Deleting local token and identity.")
|
|
102
|
+
console.error(error)
|
|
103
|
+
deleteLocalAccessToken()
|
|
104
|
+
deleteLocalBandadaIdentity()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
process.exit(0)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export default authBandada
|
|
@@ -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
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
generateValidContributionsAttestation,
|
|
23
23
|
commonTerms,
|
|
24
24
|
convertToDoubleDigits
|
|
25
|
-
} from "@
|
|
25
|
+
} from "@devtion/actions"
|
|
26
26
|
import { DocumentSnapshot, DocumentData, Firestore, onSnapshot, Timestamp } from "firebase/firestore"
|
|
27
27
|
import { Functions } from "firebase/functions"
|
|
28
28
|
import open from "open"
|
|
@@ -40,8 +40,8 @@ import {
|
|
|
40
40
|
estimateParticipantFreeGlobalDiskSpace
|
|
41
41
|
} from "../lib/utils.js"
|
|
42
42
|
import { COMMAND_ERRORS, showError } from "../lib/errors.js"
|
|
43
|
-
import { bootstrapCommandExecutionAndServices, checkAuth } from "../lib/services.js"
|
|
44
|
-
import { getAttestationLocalFilePath, localPaths } from "../lib/localConfigs.js"
|
|
43
|
+
import { authWithToken, bootstrapCommandExecutionAndServices, checkAuth } from "../lib/services.js"
|
|
44
|
+
import { checkLocalBandadaIdentity, getAttestationLocalFilePath, localPaths } from "../lib/localConfigs.js"
|
|
45
45
|
import theme from "../lib/theme.js"
|
|
46
46
|
import { checkAndMakeNewDirectoryIfNonexistent, writeFile } from "../lib/files.js"
|
|
47
47
|
|
|
@@ -419,14 +419,19 @@ export const handlePublicAttestation = async (
|
|
|
419
419
|
|
|
420
420
|
await sleep(1000) // workaround for file descriptor unexpected close.
|
|
421
421
|
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
theme.text.underlined(gistUrl)
|
|
427
|
-
)})`
|
|
428
|
-
)
|
|
422
|
+
let gistUrl = ""
|
|
423
|
+
const isBandada = checkLocalBandadaIdentity()
|
|
424
|
+
if (!isBandada) {
|
|
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
|
}
|
|
@@ -464,7 +469,6 @@ export const listenToCeremonyCircuitDocumentChanges = (
|
|
|
464
469
|
const { fullContribution, verifyCloudFunction } = avgTimings
|
|
465
470
|
const { currentContributor } = waitingQueue
|
|
466
471
|
|
|
467
|
-
// Get circuit current contributor participant document.
|
|
468
472
|
const circuitCurrentContributor = await getDocumentById(
|
|
469
473
|
firestoreDatabase,
|
|
470
474
|
getParticipantsCollectionPath(ceremonyId),
|
|
@@ -725,7 +729,8 @@ export const listenToParticipantDocumentChanges = async (
|
|
|
725
729
|
participant,
|
|
726
730
|
entropy,
|
|
727
731
|
providerUserId,
|
|
728
|
-
false // not finalizing.
|
|
732
|
+
false, // not finalizing.
|
|
733
|
+
circuits.length
|
|
729
734
|
)
|
|
730
735
|
}
|
|
731
736
|
// Scenario (3.A).
|
|
@@ -811,7 +816,9 @@ export const listenToParticipantDocumentChanges = async (
|
|
|
811
816
|
await getLatestVerificationResult(firestoreDatabase, ceremony.id, circuit.id, participant.id)
|
|
812
817
|
|
|
813
818
|
// Get next circuit for contribution.
|
|
814
|
-
const nextCircuit =
|
|
819
|
+
const nextCircuit = timeoutExpired
|
|
820
|
+
? getCircuitBySequencePosition(circuits, changedContributionProgress)
|
|
821
|
+
: getCircuitBySequencePosition(circuits, changedContributionProgress + 1)
|
|
815
822
|
|
|
816
823
|
// Check disk space requirements for participant.
|
|
817
824
|
const wannaGenerateAttestation = await handleDiskSpaceRequirementForNextContribution(
|
|
@@ -892,12 +899,13 @@ export const listenToParticipantDocumentChanges = async (
|
|
|
892
899
|
const contribute = async (opt: any) => {
|
|
893
900
|
const { firebaseApp, firebaseFunctions, firestoreDatabase } = await bootstrapCommandExecutionAndServices()
|
|
894
901
|
|
|
895
|
-
// Check for authentication.
|
|
896
|
-
const { user, providerUserId, token } = await checkAuth(firebaseApp)
|
|
897
|
-
|
|
898
902
|
// Get options.
|
|
899
903
|
const ceremonyOpt = opt.ceremony
|
|
900
904
|
const entropyOpt = opt.entropy
|
|
905
|
+
const { auth } = opt
|
|
906
|
+
|
|
907
|
+
// Check for authentication.
|
|
908
|
+
const { user, providerUserId, token } = auth ? await authWithToken(firebaseApp, auth) : await checkAuth(firebaseApp)
|
|
901
909
|
|
|
902
910
|
// Prepare data.
|
|
903
911
|
let selectedCeremony: FirebaseDocumentInfo
|
|
@@ -949,7 +957,7 @@ const contribute = async (opt: any) => {
|
|
|
949
957
|
const userData = userDoc.data()
|
|
950
958
|
if (!userData) {
|
|
951
959
|
spinner.fail(
|
|
952
|
-
`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
|
|
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.`
|
|
953
961
|
)
|
|
954
962
|
process.exit(0)
|
|
955
963
|
}
|