@devtion/devcli 0.0.0-004e6ad
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/LICENSE +21 -0
- package/README.md +120 -0
- package/dist/.env +55 -0
- package/dist/index.js +3635 -0
- package/dist/public/mini-semaphore.wasm +0 -0
- package/dist/public/mini-semaphore.zkey +0 -0
- package/dist/types/commands/auth.d.ts +25 -0
- package/dist/types/commands/authBandada.d.ts +2 -0
- package/dist/types/commands/authSIWE.d.ts +7 -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/clean.d.ts +6 -0
- package/dist/types/commands/contribute.d.ts +139 -0
- package/dist/types/commands/finalize.d.ts +52 -0
- package/dist/types/commands/index.d.ts +11 -0
- package/dist/types/commands/listCeremonies.d.ts +5 -0
- package/dist/types/commands/logout.d.ts +6 -0
- package/dist/types/commands/observe.d.ts +22 -0
- package/dist/types/commands/setup.d.ts +86 -0
- package/dist/types/commands/validate.d.ts +8 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/lib/bandada.d.ts +6 -0
- package/dist/types/lib/errors.d.ts +60 -0
- package/dist/types/lib/files.d.ts +65 -0
- package/dist/types/lib/localConfigs.d.ts +148 -0
- package/dist/types/lib/prompts.d.ts +104 -0
- package/dist/types/lib/services.d.ts +31 -0
- package/dist/types/lib/theme.d.ts +42 -0
- package/dist/types/lib/utils.d.ts +159 -0
- package/dist/types/types/index.d.ts +134 -0
- package/package.json +108 -0
- package/src/commands/auth.ts +214 -0
- package/src/commands/authBandada.ts +120 -0
- package/src/commands/authSIWE.ts +185 -0
- package/src/commands/ceremony/index.ts +20 -0
- package/src/commands/ceremony/listParticipants.ts +56 -0
- package/src/commands/clean.ts +49 -0
- package/src/commands/contribute.ts +1116 -0
- package/src/commands/finalize.ts +395 -0
- package/src/commands/index.ts +11 -0
- package/src/commands/listCeremonies.ts +31 -0
- package/src/commands/logout.ts +69 -0
- package/src/commands/observe.ts +197 -0
- package/src/commands/setup.ts +912 -0
- package/src/commands/validate.ts +28 -0
- package/src/index.ts +88 -0
- package/src/lib/bandada.ts +51 -0
- package/src/lib/errors.ts +77 -0
- package/src/lib/files.ts +102 -0
- package/src/lib/localConfigs.ts +240 -0
- package/src/lib/prompts.ts +745 -0
- package/src/lib/services.ts +214 -0
- package/src/lib/theme.ts +45 -0
- package/src/lib/utils.ts +813 -0
- package/src/types/conf.d.ts +16 -0
- package/src/types/index.ts +145 -0
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import open from "open"
|
|
3
|
+
import {
|
|
4
|
+
isCoordinator,
|
|
5
|
+
getClosedCeremonies,
|
|
6
|
+
getDocumentById,
|
|
7
|
+
getParticipantsCollectionPath,
|
|
8
|
+
checkAndPrepareCoordinatorForFinalization,
|
|
9
|
+
getCeremonyCircuits,
|
|
10
|
+
getVerificationKeyStorageFilePath,
|
|
11
|
+
getBucketName,
|
|
12
|
+
multiPartUpload,
|
|
13
|
+
getVerifierContractStorageFilePath,
|
|
14
|
+
finalizeCeremony,
|
|
15
|
+
generateValidContributionsAttestation,
|
|
16
|
+
commonTerms,
|
|
17
|
+
finalContributionIndex,
|
|
18
|
+
computeSHA256ToHex,
|
|
19
|
+
finalizeCircuit,
|
|
20
|
+
verificationKeyAcronym,
|
|
21
|
+
verifierSmartContractAcronym,
|
|
22
|
+
exportVerifierContract,
|
|
23
|
+
FirebaseDocumentInfo,
|
|
24
|
+
exportVkey
|
|
25
|
+
} from "@devtion/actions"
|
|
26
|
+
import { Functions } from "firebase/functions"
|
|
27
|
+
import { Firestore } from "firebase/firestore"
|
|
28
|
+
import { dirname } from "path"
|
|
29
|
+
import { fileURLToPath } from "url"
|
|
30
|
+
import { COMMAND_ERRORS, showError } from "../lib/errors.js"
|
|
31
|
+
import {
|
|
32
|
+
customSpinner,
|
|
33
|
+
generateCustomUrlToTweetAboutParticipation,
|
|
34
|
+
handleStartOrResumeContribution,
|
|
35
|
+
publishGist,
|
|
36
|
+
sleep,
|
|
37
|
+
terminate
|
|
38
|
+
} from "../lib/utils.js"
|
|
39
|
+
import { authWithToken, bootstrapCommandExecutionAndServices, checkAuth } from "../lib/services.js"
|
|
40
|
+
import {
|
|
41
|
+
getFinalAttestationLocalFilePath,
|
|
42
|
+
getFinalZkeyLocalFilePath,
|
|
43
|
+
getVerificationKeyLocalFilePath,
|
|
44
|
+
getVerifierContractLocalFilePath,
|
|
45
|
+
localPaths
|
|
46
|
+
} from "../lib/localConfigs.js"
|
|
47
|
+
import theme from "../lib/theme.js"
|
|
48
|
+
import { checkAndMakeNewDirectoryIfNonexistent, writeLocalJsonFile, writeFile } from "../lib/files.js"
|
|
49
|
+
import { promptForCeremonySelection, promptToTypeEntropyOrBeacon } from "../lib/prompts.js"
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Export and store on the ceremony bucket the verification key for the given final contribution.
|
|
53
|
+
* @param cloudFunctions <Functions> - the instance of the Firebase cloud functions for the application.
|
|
54
|
+
* @param bucketName <string> - the name of the ceremony bucket.
|
|
55
|
+
* @param finalZkeyLocalFilePath <string> - the local file path of the final zKey.
|
|
56
|
+
* @param verificationKeyLocalFilePath <string> - the local file path of the verification key.
|
|
57
|
+
* @param verificationKeyStorageFilePath <string> - the storage file path of the verification key.
|
|
58
|
+
*/
|
|
59
|
+
export const handleVerificationKey = async (
|
|
60
|
+
cloudFunctions: Functions,
|
|
61
|
+
bucketName: string,
|
|
62
|
+
finalZkeyLocalFilePath: string,
|
|
63
|
+
verificationKeyLocalFilePath: string,
|
|
64
|
+
verificationKeyStorageFilePath: string
|
|
65
|
+
) => {
|
|
66
|
+
const spinner = customSpinner(`Exporting the verification key...`, "clock")
|
|
67
|
+
spinner.start()
|
|
68
|
+
|
|
69
|
+
// Export the verification key.
|
|
70
|
+
const vKey = await exportVkey(finalZkeyLocalFilePath)
|
|
71
|
+
|
|
72
|
+
spinner.text = "Writing verification key..."
|
|
73
|
+
|
|
74
|
+
// Write the verification key locally.
|
|
75
|
+
writeLocalJsonFile(verificationKeyLocalFilePath, vKey)
|
|
76
|
+
|
|
77
|
+
await sleep(3000) // workaround for file descriptor.
|
|
78
|
+
|
|
79
|
+
// Upload verification key to storage.
|
|
80
|
+
await multiPartUpload(
|
|
81
|
+
cloudFunctions,
|
|
82
|
+
bucketName,
|
|
83
|
+
verificationKeyStorageFilePath,
|
|
84
|
+
verificationKeyLocalFilePath,
|
|
85
|
+
Number(process.env.CONFIG_STREAM_CHUNK_SIZE_IN_MB)
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
spinner.succeed(`Verification key correctly saved on storage`)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Derive and store on the ceremony bucket the Solidity Verifier smart contract for the given final contribution.
|
|
93
|
+
* @param cloudFunctions <Functions> - the instance of the Firebase cloud functions for the application.
|
|
94
|
+
* @param bucketName <string> - the name of the ceremony bucket.
|
|
95
|
+
* @param finalZkeyLocalFilePath <string> - the local file path of the final zKey.
|
|
96
|
+
* @param verifierContractLocalFilePath <string> - the local file path of the verifier smart contract.
|
|
97
|
+
* @param verifierContractStorageFilePath <string> - the storage file path of the verifier smart contract.
|
|
98
|
+
*/
|
|
99
|
+
export const handleVerifierSmartContract = async (
|
|
100
|
+
cloudFunctions: Functions,
|
|
101
|
+
bucketName: string,
|
|
102
|
+
finalZkeyLocalFilePath: string,
|
|
103
|
+
verifierContractLocalFilePath: string,
|
|
104
|
+
verifierContractStorageFilePath: string
|
|
105
|
+
) => {
|
|
106
|
+
const spinner = customSpinner(`Extracting verifier contract...`, `clock`)
|
|
107
|
+
spinner.start()
|
|
108
|
+
|
|
109
|
+
// Verifier path.
|
|
110
|
+
const packagePath = `${dirname(fileURLToPath(import.meta.url))}`
|
|
111
|
+
const verifierPath = packagePath.includes(`src/commands`)
|
|
112
|
+
? `${dirname(
|
|
113
|
+
fileURLToPath(import.meta.url)
|
|
114
|
+
)}/../../../../node_modules/snarkjs/templates/verifier_groth16.sol.ejs`
|
|
115
|
+
: `${dirname(fileURLToPath(import.meta.url))}/../node_modules/snarkjs/templates/verifier_groth16.sol.ejs`
|
|
116
|
+
|
|
117
|
+
// Export the Solidity verifier smart contract.
|
|
118
|
+
const verifierCode = await exportVerifierContract(finalZkeyLocalFilePath, verifierPath)
|
|
119
|
+
|
|
120
|
+
spinner.text = `Writing verifier smart contract...`
|
|
121
|
+
|
|
122
|
+
// Write the verification key locally.
|
|
123
|
+
writeFile(verifierContractLocalFilePath, verifierCode)
|
|
124
|
+
|
|
125
|
+
await sleep(3000) // workaround for file descriptor.
|
|
126
|
+
|
|
127
|
+
// Upload verifier smart contract to storage.
|
|
128
|
+
await multiPartUpload(
|
|
129
|
+
cloudFunctions,
|
|
130
|
+
bucketName,
|
|
131
|
+
verifierContractStorageFilePath,
|
|
132
|
+
verifierContractLocalFilePath,
|
|
133
|
+
Number(process.env.CONFIG_STREAM_CHUNK_SIZE_IN_MB)
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
spinner.succeed(`Verifier smart contract correctly saved on storage`)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Handle the process of finalizing a ceremony circuit.
|
|
141
|
+
* @dev this process results in the extraction of the final ceremony artifacts for the calculation and verification of proofs.
|
|
142
|
+
* @notice this method must enforce the order among these steps:
|
|
143
|
+
* 1) Compute the final contribution (zKey).
|
|
144
|
+
* 2) Extract the verification key (vKey).
|
|
145
|
+
* 3) Extract the Verifier smart contract (.sol).
|
|
146
|
+
* 4) Upload the artifacts in the AWS S3 storage.
|
|
147
|
+
* 5) Complete the final contribution data w/ artifacts references and hashes (cloud function).
|
|
148
|
+
* @param cloudFunctions <Functions> - the instance of the Firebase cloud functions for the application.
|
|
149
|
+
* @param firestoreDatabase <Firestore> - the Firestore service instance associated to the current Firebase application.
|
|
150
|
+
* @param ceremony <FirebaseDocumentInfo> - the Firestore document of the ceremony.
|
|
151
|
+
* @param circuit <FirebaseDocumentInfo> - the Firestore document of the ceremony circuit.
|
|
152
|
+
* @param participant <FirebaseDocumentInfo> - the Firestore document of the participant (coordinator).
|
|
153
|
+
* @param beacon <string> - the value used to compute the final contribution while finalizing the ceremony.
|
|
154
|
+
* @param coordinatorIdentifier <string> - the identifier of the coordinator.
|
|
155
|
+
* @param circuitsLength <number> - the number of circuits in the ceremony.
|
|
156
|
+
*/
|
|
157
|
+
export const handleCircuitFinalization = async (
|
|
158
|
+
cloudFunctions: Functions,
|
|
159
|
+
firestoreDatabase: Firestore,
|
|
160
|
+
ceremony: FirebaseDocumentInfo,
|
|
161
|
+
circuit: FirebaseDocumentInfo,
|
|
162
|
+
participant: FirebaseDocumentInfo,
|
|
163
|
+
beacon: string,
|
|
164
|
+
coordinatorIdentifier: string,
|
|
165
|
+
circuitsLength: number
|
|
166
|
+
) => {
|
|
167
|
+
// Step (1).
|
|
168
|
+
await handleStartOrResumeContribution(
|
|
169
|
+
cloudFunctions,
|
|
170
|
+
firestoreDatabase,
|
|
171
|
+
ceremony,
|
|
172
|
+
circuit,
|
|
173
|
+
participant,
|
|
174
|
+
computeSHA256ToHex(beacon),
|
|
175
|
+
coordinatorIdentifier,
|
|
176
|
+
true,
|
|
177
|
+
circuitsLength
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
await sleep(2000) // workaround for descriptors.
|
|
181
|
+
|
|
182
|
+
// Extract data.
|
|
183
|
+
const { prefix: circuitPrefix } = circuit.data
|
|
184
|
+
const { prefix: ceremonyPrefix } = ceremony.data
|
|
185
|
+
|
|
186
|
+
// Prepare local paths.
|
|
187
|
+
const finalZkeyLocalFilePath = getFinalZkeyLocalFilePath(`${circuitPrefix}_${finalContributionIndex}.zkey`)
|
|
188
|
+
const verificationKeyLocalFilePath = getVerificationKeyLocalFilePath(
|
|
189
|
+
`${circuitPrefix}_${verificationKeyAcronym}.json`
|
|
190
|
+
)
|
|
191
|
+
const verifierContractLocalFilePath = getVerifierContractLocalFilePath(
|
|
192
|
+
`${circuitPrefix}_${verifierSmartContractAcronym}.sol`
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
// Prepare storage paths.
|
|
196
|
+
const verificationKeyStorageFilePath = getVerificationKeyStorageFilePath(
|
|
197
|
+
circuitPrefix,
|
|
198
|
+
`${circuitPrefix}_${verificationKeyAcronym}.json`
|
|
199
|
+
)
|
|
200
|
+
const verifierContractStorageFilePath = getVerifierContractStorageFilePath(
|
|
201
|
+
circuitPrefix,
|
|
202
|
+
`${circuitPrefix}_${verifierSmartContractAcronym}.sol`
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
// Get ceremony bucket.
|
|
206
|
+
const bucketName = getBucketName(ceremonyPrefix, String(process.env.CONFIG_CEREMONY_BUCKET_POSTFIX))
|
|
207
|
+
|
|
208
|
+
// Step (2 & 4).
|
|
209
|
+
await handleVerificationKey(
|
|
210
|
+
cloudFunctions,
|
|
211
|
+
bucketName,
|
|
212
|
+
finalZkeyLocalFilePath,
|
|
213
|
+
verificationKeyLocalFilePath,
|
|
214
|
+
verificationKeyStorageFilePath
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
// Step (3 & 4).
|
|
218
|
+
await handleVerifierSmartContract(
|
|
219
|
+
cloudFunctions,
|
|
220
|
+
bucketName,
|
|
221
|
+
finalZkeyLocalFilePath,
|
|
222
|
+
verifierContractLocalFilePath,
|
|
223
|
+
verifierContractStorageFilePath
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
// Step (5).
|
|
227
|
+
const spinner = customSpinner(`Wrapping up the finalization of the circuit...`, `clock`)
|
|
228
|
+
spinner.start()
|
|
229
|
+
|
|
230
|
+
// Finalize circuit contribution.
|
|
231
|
+
await finalizeCircuit(cloudFunctions, ceremony.id, circuit.id, bucketName, beacon)
|
|
232
|
+
|
|
233
|
+
await sleep(2000)
|
|
234
|
+
|
|
235
|
+
spinner.succeed(`Circuit has been finalized correctly`)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Finalize command.
|
|
240
|
+
* @notice The finalize command allows a coordinator to finalize a Trusted Setup Phase 2 ceremony by providing the final beacon,
|
|
241
|
+
* computing the final zKeys and extracting the Verifier Smart Contract + Verification Keys per each ceremony circuit.
|
|
242
|
+
* anyone could use the final zKey to create a proof and everyone else could verify the correctness using the
|
|
243
|
+
* related verification key (off-chain) or Verifier smart contract (on-chain).
|
|
244
|
+
* @dev For proper execution, the command requires the coordinator to be authenticated with a GitHub account (run auth command first) in order to
|
|
245
|
+
* handle sybil-resistance and connect to GitHub APIs to publish the gist containing the final public attestation.
|
|
246
|
+
*/
|
|
247
|
+
const finalize = async (opt: any) => {
|
|
248
|
+
const { firebaseApp, firebaseFunctions, firestoreDatabase } = await bootstrapCommandExecutionAndServices()
|
|
249
|
+
|
|
250
|
+
// Check for authentication.
|
|
251
|
+
const { auth } = opt
|
|
252
|
+
const {
|
|
253
|
+
user,
|
|
254
|
+
providerUserId,
|
|
255
|
+
token: coordinatorAccessToken
|
|
256
|
+
} = auth ? await authWithToken(firebaseApp, auth) : await checkAuth(firebaseApp)
|
|
257
|
+
|
|
258
|
+
// Preserve command execution only for coordinators.
|
|
259
|
+
if (!(await isCoordinator(user))) showError(COMMAND_ERRORS.COMMAND_NOT_COORDINATOR, true)
|
|
260
|
+
|
|
261
|
+
// Retrieve the closed ceremonies (ready for finalization).
|
|
262
|
+
const ceremoniesClosedForFinalization = await getClosedCeremonies(firestoreDatabase)
|
|
263
|
+
|
|
264
|
+
// Gracefully exit if no ceremonies are closed and ready for finalization.
|
|
265
|
+
if (!ceremoniesClosedForFinalization.length) showError(COMMAND_ERRORS.COMMAND_FINALIZED_NO_CLOSED_CEREMONIES, true)
|
|
266
|
+
|
|
267
|
+
console.log(
|
|
268
|
+
`${theme.symbols.warning} The computation of the final contribution could take the bulk of your computational resources and memory based on the size of the circuit ${theme.emojis.fire}\n`
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
// Prompt for ceremony selection.
|
|
272
|
+
const selectedCeremony = await promptForCeremonySelection(
|
|
273
|
+
ceremoniesClosedForFinalization,
|
|
274
|
+
true,
|
|
275
|
+
"Which ceremony would you like to finalize?"
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
// Get coordinator participant document.
|
|
279
|
+
let participant = await getDocumentById(
|
|
280
|
+
firestoreDatabase,
|
|
281
|
+
getParticipantsCollectionPath(selectedCeremony.id),
|
|
282
|
+
user.uid
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
const isCoordinatorReadyForCeremonyFinalization = await checkAndPrepareCoordinatorForFinalization(
|
|
286
|
+
firebaseFunctions,
|
|
287
|
+
selectedCeremony.id
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
if (!isCoordinatorReadyForCeremonyFinalization)
|
|
291
|
+
showError(COMMAND_ERRORS.COMMAND_FINALIZED_NOT_READY_FOR_FINALIZATION, true)
|
|
292
|
+
|
|
293
|
+
// Prompt for beacon.
|
|
294
|
+
const beacon = await promptToTypeEntropyOrBeacon(false)
|
|
295
|
+
// Compute hash
|
|
296
|
+
const beaconHash = computeSHA256ToHex(beacon)
|
|
297
|
+
// Display.
|
|
298
|
+
console.log(`${theme.symbols.info} Beacon SHA256 hash ${theme.text.bold(beaconHash)}`)
|
|
299
|
+
|
|
300
|
+
// Clean directories.
|
|
301
|
+
checkAndMakeNewDirectoryIfNonexistent(localPaths.output)
|
|
302
|
+
checkAndMakeNewDirectoryIfNonexistent(localPaths.finalize)
|
|
303
|
+
checkAndMakeNewDirectoryIfNonexistent(localPaths.finalZkeys)
|
|
304
|
+
checkAndMakeNewDirectoryIfNonexistent(localPaths.finalPot)
|
|
305
|
+
checkAndMakeNewDirectoryIfNonexistent(localPaths.finalAttestations)
|
|
306
|
+
checkAndMakeNewDirectoryIfNonexistent(localPaths.verificationKeys)
|
|
307
|
+
checkAndMakeNewDirectoryIfNonexistent(localPaths.verifierContracts)
|
|
308
|
+
|
|
309
|
+
// Get ceremony circuits.
|
|
310
|
+
const circuits = await getCeremonyCircuits(firestoreDatabase, selectedCeremony.id)
|
|
311
|
+
|
|
312
|
+
// Handle finalization for each ceremony circuit.
|
|
313
|
+
for await (const circuit of circuits)
|
|
314
|
+
await handleCircuitFinalization(
|
|
315
|
+
firebaseFunctions,
|
|
316
|
+
firestoreDatabase,
|
|
317
|
+
selectedCeremony,
|
|
318
|
+
circuit,
|
|
319
|
+
participant,
|
|
320
|
+
beacon,
|
|
321
|
+
providerUserId,
|
|
322
|
+
circuits.length
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
process.stdout.write(`\n`)
|
|
326
|
+
|
|
327
|
+
const spinner = customSpinner(`Wrapping up the finalization of the ceremony...`, "clock")
|
|
328
|
+
spinner.start()
|
|
329
|
+
|
|
330
|
+
// Finalize the ceremony.
|
|
331
|
+
await finalizeCeremony(firebaseFunctions, selectedCeremony.id)
|
|
332
|
+
|
|
333
|
+
spinner.succeed(
|
|
334
|
+
`Great, you have completed the finalization of the ${theme.text.bold(selectedCeremony.data.title)} ceremony ${
|
|
335
|
+
theme.emojis.tada
|
|
336
|
+
}\n`
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
// Get updated coordinator participant document.
|
|
340
|
+
participant = await getDocumentById(firestoreDatabase, getParticipantsCollectionPath(selectedCeremony.id), user.uid)
|
|
341
|
+
|
|
342
|
+
// Extract updated data.
|
|
343
|
+
const { contributions } = participant.data()!
|
|
344
|
+
const { prefix, title: ceremonyName } = selectedCeremony.data
|
|
345
|
+
|
|
346
|
+
// Generate attestation with final contributions.
|
|
347
|
+
const publicAttestation = await generateValidContributionsAttestation(
|
|
348
|
+
firestoreDatabase,
|
|
349
|
+
circuits,
|
|
350
|
+
selectedCeremony.id,
|
|
351
|
+
participant.id,
|
|
352
|
+
contributions,
|
|
353
|
+
providerUserId,
|
|
354
|
+
ceremonyName,
|
|
355
|
+
true
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
// Write public attestation locally.
|
|
359
|
+
writeFile(
|
|
360
|
+
getFinalAttestationLocalFilePath(
|
|
361
|
+
`${prefix}_${finalContributionIndex}_${commonTerms.foldersAndPathsTerms.attestation}.log`
|
|
362
|
+
),
|
|
363
|
+
Buffer.from(publicAttestation)
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
await sleep(3000) // workaround for file descriptor unexpected close.
|
|
367
|
+
|
|
368
|
+
const gistUrl = await publishGist(coordinatorAccessToken, publicAttestation, ceremonyName, prefix)
|
|
369
|
+
|
|
370
|
+
console.log(
|
|
371
|
+
`\n${
|
|
372
|
+
theme.symbols.info
|
|
373
|
+
} Your public final attestation has been successfully posted as Github Gist (${theme.text.bold(
|
|
374
|
+
theme.text.underlined(gistUrl)
|
|
375
|
+
)})`
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
// Generate a ready to share custom url to tweet about ceremony participation.
|
|
379
|
+
const tweetUrl = generateCustomUrlToTweetAboutParticipation(ceremonyName, gistUrl, true)
|
|
380
|
+
|
|
381
|
+
console.log(
|
|
382
|
+
`${
|
|
383
|
+
theme.symbols.info
|
|
384
|
+
} We encourage you to tweet about the ceremony finalization by clicking the link below\n\n${theme.text.underlined(
|
|
385
|
+
tweetUrl
|
|
386
|
+
)}`
|
|
387
|
+
)
|
|
388
|
+
|
|
389
|
+
// Automatically open a webpage with the tweet.
|
|
390
|
+
await open(tweetUrl)
|
|
391
|
+
|
|
392
|
+
terminate(providerUserId)
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
export default finalize
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { default as setup } from "./setup.js"
|
|
2
|
+
export { default as auth } from "./auth.js"
|
|
3
|
+
export { default as authBandada } from "./authBandada.js"
|
|
4
|
+
export { default as authSIWE } from "./authSIWE.js"
|
|
5
|
+
export { default as contribute } from "./contribute.js"
|
|
6
|
+
export { default as observe } from "./observe.js"
|
|
7
|
+
export { default as finalize } from "./finalize.js"
|
|
8
|
+
export { default as clean } from "./clean.js"
|
|
9
|
+
export { default as logout } from "./logout.js"
|
|
10
|
+
export { default as validate } from "./validate.js"
|
|
11
|
+
export { default as listCeremonies } from "./listCeremonies.js"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { commonTerms, getAllCollectionDocs } from "@devtion/actions"
|
|
2
|
+
import { showError } from "../lib/errors.js"
|
|
3
|
+
import { bootstrapCommandExecutionAndServices } from "../lib/services.js"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Validate ceremony setup command.
|
|
7
|
+
*/
|
|
8
|
+
const listCeremonies = async () => {
|
|
9
|
+
try {
|
|
10
|
+
// bootstrap command execution and services
|
|
11
|
+
const { firestoreDatabase } = await bootstrapCommandExecutionAndServices()
|
|
12
|
+
|
|
13
|
+
// get all ceremonies
|
|
14
|
+
const ceremonies = await getAllCollectionDocs(firestoreDatabase, commonTerms.collections.ceremonies.name)
|
|
15
|
+
// store all names
|
|
16
|
+
const names: string[] = []
|
|
17
|
+
|
|
18
|
+
// loop through all ceremonies
|
|
19
|
+
for (const ceremony of ceremonies) names.push(ceremony.data().prefix)
|
|
20
|
+
|
|
21
|
+
// print them to the console
|
|
22
|
+
console.log(names.join(", "))
|
|
23
|
+
process.exit(0)
|
|
24
|
+
} catch (err: any) {
|
|
25
|
+
showError(`${err.toString()}`, false)
|
|
26
|
+
// we want to exit with a non-zero exit code
|
|
27
|
+
process.exit(1)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default listCeremonies
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { getAuth, signOut } from "firebase/auth"
|
|
4
|
+
import { bootstrapCommandExecutionAndServices, checkAuth } from "../lib/services.js"
|
|
5
|
+
import { showError } from "../lib/errors.js"
|
|
6
|
+
import { askForConfirmation } from "../lib/prompts.js"
|
|
7
|
+
import { customSpinner, sleep, terminate } from "../lib/utils.js"
|
|
8
|
+
import theme from "../lib/theme.js"
|
|
9
|
+
import { deleteLocalAccessToken, deleteLocalAuthMethod, deleteLocalBandadaIdentity } from "../lib/localConfigs.js"
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Logout command.
|
|
13
|
+
*/
|
|
14
|
+
const logout = async () => {
|
|
15
|
+
try {
|
|
16
|
+
// Initialize services.
|
|
17
|
+
const { firebaseApp } = await bootstrapCommandExecutionAndServices()
|
|
18
|
+
|
|
19
|
+
// Check for authentication.
|
|
20
|
+
const { providerUserId } = await checkAuth(firebaseApp)
|
|
21
|
+
|
|
22
|
+
// Inform the user about deassociation in Github and re run auth
|
|
23
|
+
console.log(
|
|
24
|
+
`${
|
|
25
|
+
theme.symbols.warning
|
|
26
|
+
} The logout could sign you out from Firebase and will delete the access token saved locally on this machine. Therefore, you have to run ${theme.text.bold(
|
|
27
|
+
"phase2cli auth"
|
|
28
|
+
)} to authenticate again.\n${
|
|
29
|
+
theme.symbols.info
|
|
30
|
+
} Remember, we cannot revoke the authorization from your Github account from this CLI! You can do this manually as reported in the official Github documentation ${
|
|
31
|
+
theme.emojis.pointDown
|
|
32
|
+
}\n\n${theme.text.bold(
|
|
33
|
+
theme.text.underlined(
|
|
34
|
+
`https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/reviewing-your-authorized-applications-oauth`
|
|
35
|
+
)
|
|
36
|
+
)}\n`
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
// Ask for confirmation.
|
|
40
|
+
const { confirmation } = await askForConfirmation(
|
|
41
|
+
"Are you sure you want to log out from this machine?",
|
|
42
|
+
"Yes",
|
|
43
|
+
"No"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
if (confirmation) {
|
|
47
|
+
const spinner = customSpinner(`Logging out...`, "clock")
|
|
48
|
+
spinner.start()
|
|
49
|
+
|
|
50
|
+
// Sign out.
|
|
51
|
+
const auth = getAuth()
|
|
52
|
+
await signOut(auth)
|
|
53
|
+
|
|
54
|
+
// Delete local token.
|
|
55
|
+
deleteLocalAuthMethod()
|
|
56
|
+
deleteLocalAccessToken()
|
|
57
|
+
deleteLocalBandadaIdentity()
|
|
58
|
+
|
|
59
|
+
await sleep(3000) // ~3s.
|
|
60
|
+
|
|
61
|
+
spinner.stop()
|
|
62
|
+
console.log(`${theme.symbols.success} Logout successfully completed`)
|
|
63
|
+
} else terminate(providerUserId)
|
|
64
|
+
} catch (err: any) {
|
|
65
|
+
showError(`Something went wrong: ${err.toString()}`, true)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export default logout
|